传送门


注意到每一次\(1\ x\)操作相当于一次LCT中的access操作。由LCT复杂度证明可以知道access的总次数不会超过\(O(nlogn)\),我们只需要模拟这个access的过程并在其中动态统计每一个点的答案。

我们考虑在虚实边切换的过程中即时更新答案。设当前即将把\(y \rightarrow x\)的虚边转换为实边,设此时\(x\)的实儿子为\(p\)。那么对于\(p\)及其子树,所有点到根的路径经过的颜色数量均\(+1\);对于\(y\)及其所有点的子树,它们经过的颜色的数量均\(-1\)。那么我们只需要实现子树加减,可以使用线段树。

对于\(3\)操作也就是一个子树\(\max\)操作,同样在线段树上维护;\(2\)操作可以知道\(val_{x,y} = val_{1,x} + val_{1,y} - 2val_{1,LCA(x,y)} + 1\),所以就是线段树上的单点查询。

#include<bits/stdc++.h>
using namespace std;int read(){int a = 0; char c = getchar(); bool f = 0;while(!isdigit(c)){f = c == '-'; c = getchar();}while(isdigit(c)){a = a * 10 + c - 48; c = getchar();}return f ? -a : a;
}const int _ = 1e5 + 7;
vector < int > ch[_];
int N , M , dep[_] , dfn[_] , sz[_] , ind[_] , ts , jump[_][20];namespace segt{int mx[_ << 2] , mrk[_ << 2];#define mid ((l + r) >> 1)
#define lch (x << 1)
#define rch (x << 1 | 1)void init(int x , int l , int r){if(l == r) mx[x] = dep[ind[l]];else{init(lch , l , mid); init(rch , mid + 1 , r); mx[x] = max(mx[lch] , mx[rch]);}}void mark(int x , int val){mrk[x] += val; mx[x] += val;}void down(int x){mark(lch , mrk[x]); mark(rch , mrk[x]); mrk[x] = 0;}void modify(int x , int l , int r , int L , int R , int val){if(l >= L && r <= R) return mark(x , val);down(x);if(mid >= L) modify(lch , l , mid , L , R , val);if(mid < R) modify(rch , mid + 1 , r , L , R , val);mx[x] = max(mx[lch] , mx[rch]);}int qry(int x , int l , int r , int L , int R){if(l >= L && r <= R) return mx[x];int mx = 0; down(x);if(mid >= L) mx = qry(lch , l , mid , L , R);if(mid < R) mx = max(mx , qry(rch , mid + 1 , r , L , R));return mx;}
#undef lch
#undef rch
}namespace LCT{int fa[_] , ch[_][2];bool son(int x){return ch[fa[x]][1] == x;}bool nroot(int x){return ch[fa[x]][1] == x || ch[fa[x]][0] == x;}void rot(int x){bool f = son(x); int y = fa[x] , z = fa[y] , w = ch[x][f ^ 1];fa[x] = z; if(nroot(y)) ch[z][son(y)] = x;fa[y] = x; ch[x][f ^ 1] = y;ch[y][f] = w; if(w) fa[w] = y;}void splay(int x){while(nroot(x)){if(nroot(fa[x])) rot(son(fa[x]) == son(x) ? fa[x] : x); rot(x);}}void access(int x){for(int y = 0 ; x ; y = x , x = fa[x]){splay(x); if(ch[x][1]){int t = ch[x][1]; while(ch[t][0]) t = ch[t][0];segt::modify(1 , 1 , N , dfn[t] , dfn[t] + sz[t] - 1 , 1);}if(y){int t = y; while(ch[t][0]) t = ch[t][0];segt::modify(1 , 1 , N , dfn[t] , dfn[t] + sz[t] - 1 , -1);}ch[x][1] = y; fa[y] = x;}}
}void dfs(int x , int p){dep[x] = dep[p] + 1; ind[dfn[x] = ++ts] = x; sz[x] = 1;jump[x][0] = p; LCT::fa[x] = p;for(int i = 1 ; jump[x][i - 1] ; ++i) jump[x][i] = jump[jump[x][i - 1]][i - 1];for(auto t : ch[x]) if(t != p){dfs(t , x); sz[x] += sz[t];}
}int LCA(int x , int y){if(dep[x] < dep[y]) swap(x , y);for(int i = 18 ; i >= 0 ; --i)if(dep[x] - (1 << i) >= dep[y]) x = jump[x][i];if(x == y) return x;for(int i = 18 ; i >= 0 ; --i)if(jump[x][i] != jump[y][i]){x = jump[x][i]; y = jump[y][i];}return jump[x][0];
}int main(){
#ifndef ONLINE_JUDGEfreopen("in","r",stdin);freopen("out","w",stdout);
#endifN = read(); M = read();for(int i = 1 ; i < N ; ++i){int a = read() , b = read();ch[a].push_back(b); ch[b].push_back(a);}dfs(1 , 0); segt::init(1 , 1 , N); int x , y , z;while(M--)switch(read()){case 1: LCT::access(read()); break;case 2:x = read(); y = read(); z = LCA(x , y);printf("%d\n" , segt::qry(1 , 1 , N , dfn[x] , dfn[x]) + segt::qry(1 , 1 , N , dfn[y] , dfn[y])- 2 * segt::qry(1 , 1 , N , dfn[z] , dfn[z]) + 1); break;case 3: x = read(); printf("%d\n" , segt::qry(1 , 1 , N , dfn[x] , dfn[x] + sz[x] - 1));}return 0;
}

转载于:https://www.cnblogs.com/Itst/p/11509237.html

LOJ2001 SDOI2017 树点涂色 LCT、线段树相关推荐

  1. 【BZOJ4817】【SDOI2017】树点涂色 [LCT][线段树]

    树点涂色 Time Limit: 10 Sec  Memory Limit: 128 MB [Submit][Status][Discuss] Description Bob有一棵n个点的有根树,其中 ...

  2. [Bzoj4817] [Sdoi2017]树点涂色 (LCT神题)

    4817: [Sdoi2017]树点涂色 Time Limit: 10 Sec  Memory Limit: 128 MB Submit: 629  Solved: 371 [Submit][Stat ...

  3. 【线段树】【LCT】【LCA】树点涂色(luogu 3703)

    树点涂色 luogu 3703 题目大意 给出一棵树,每个节点的初始颜色不同,做若干操作: 1.在一个点到根节点路径上染上一种新的颜色 2.查询一条路径上有多少种不同的颜色 3.查询一个点x,使该点到 ...

  4. BZOJ 4817: [Sdoi2017]树点涂色

    4817: [Sdoi2017]树点涂色 Time Limit: 10 Sec  Memory Limit: 128 MB Submit: 273  Solved: 164 [Submit][Stat ...

  5. P6242-[模板]线段树3【吉司机线段树】

    正题 题目链接:https://www.luogu.com.cn/problem/P6242 题目大意 给出一个长度为nnn的序列aaa,mmm次要求支持操作 区间加上一个值kkk 区间所有aia_i ...

  6. 【BZOJ4515】游戏,树链剖分+永久化标记线段树维护线段信息(李超线段树)

    Time:2016.05.10 Author:xiaoyimi 转载注明出处谢谢 传送门 思路: 李超线段树 一开始听faebdc讲,并没有听的很懂ww 后来找到良心博文啊有木有 折越 首先可以把修改 ...

  7. BZOJ4012[HNOI2015]开店——树链剖分+可持久化线段树/动态点分治+vector

    题目描述 风见幽香有一个好朋友叫八云紫,她们经常一起看星星看月亮从诗词歌赋谈到 人生哲学.最近她们灵机一动,打算在幻想乡开一家小店来做生意赚点钱.这样的 想法当然非常好啦,但是她们也发现她们面临着一个 ...

  8. 线段树简单入门 (含普通线段树, zkw线段树, 主席树)

    线段树简单入门 递归版线段树 线段树的定义 线段树, 顾名思义, 就是每个节点表示一个区间. 线段树通常维护一些区间的值, 例如区间和. 比如, 上图 \([2, 5]\) 区间的和, 为以下区间的和 ...

  9. BZOJ 4817: [Sdoi2017]树点涂色(LCT+树剖+线段树)

    题目描述 Bob有一棵 nn 个点的有根树,其中1号点是根节点.Bob在每个点上涂了颜色,并且每个点上的颜色不同. 定义一条路径的权值是:这条路径上的点(包括起点和终点)共有多少种不同的颜色. Bob ...

  10. P3703-[SDOI2017]树点涂色【LCT,线段树】

    正题 题目链接:https://www.luogu.com.cn/problem/P3703 题目大意 nnn个点的一棵树开始所有点有不同的颜色,mmm次操作 将根节点到xxx节点的路径上染上一种新的 ...

最新文章

  1. 联机分析处理(OLAP)简介
  2. 《随笔记录》20170310
  3. Java联网技术之一HTTP
  4. PHP中用于精确计算的bcmath扩展
  5. Qt Creator查找和更换
  6. 商业|商务海报篇-简洁华丽的商务海报
  7. 《ETL原理及应用》学习笔记 ·004【kettle的使用-2】
  8. Vijos P1097 合并果子【哈夫曼树+优先队列】
  9. Java static的使用
  10. 【转】ajax发送请求时候为什么会报拒绝设置不安全的header
  11. Eclipse导入Android项目 Eclipse常见错误 中文乱码问题
  12. 模板题——堆排序 哈希表 字符串哈希
  13. java实现身份证号码的严格校验!
  14. PipeCAD 简介
  15. iReport制作EXCEL、PDF或者HTML文件
  16. 互联网日报 | 微博开启视频号内测;淘宝正式进军教育领域;小米声学语音技术实现全面自研...
  17. hashmap面试题,音视频学习指南来咯,社招面试心得
  18. 基于EasyNVR摄像机无插件直播方案二次开发实现自己的摄像机IPC-NVR无插件化直播解决方案
  19. 五大电影三部曲的DVD
  20. 牛客刷题笔记-数据库选择题(201-300)

热门文章

  1. python求解LeetCode习题Find Peak Element in Given num_list
  2. python '/'与'//'学习
  3. gvdp哪个工厂用_ppr铝塑管和ppr水管哪个更适合家装?
  4. 同质化代币和非同质化代币 区别对比
  5. FISCO BCOS PBFT是什么 基础流程
  6. 小学计算机老师师德师风演讲稿,2015年小学教师师德师风演讲稿
  7. 用php解二元一次方程程序,编写一个程序,求二元一次方程组,编写一个程序,求二元一次方程组的解...
  8. 计算机科学与技术志愿意愿,高考志愿填报如何得高分
  9. Java TCP案例网络聊天室
  10. 无用小知识-递归的使用