题意

有操作

$0$ $u$:询问有多少个节点 $v$ 满足路径 $u$ 到 $v$ 上所有节点(包括)都拥有相同的颜色
$1$ $u$:翻转 $u$ 的颜色

题解

直接用一个 $LCT$ 去暴力删边连边显然会 $T$

那么只有两个颜色的话就可以建两棵 $LCT$ ,观察到每次单点修改颜色时其子树所包含连通块在原颜色树上与其父亲所代表连通块断开,所以可以看作断开与父节点的边(实际上是点化边的思想),那么其它常规操作即可

注意要建个虚拟节点作为根节点的父亲

注意 $0$ 操作询问的输出,详细解释有在代码注释中给出

代码

 #include <iostream>
#include <cstdio>
#include <cstring> using namespace std; const int MAXN = 1e06 + ;
const int MAXM = 1e06 + ; struct LinkedForwardStar {
int to; int next;
} ; LinkedForwardStar Link[MAXM << ];
int Head[MAXN]= {};
int size = ; void Insert (int u, int v) {
Link[++ size].to = v;
Link[size].next = Head[u]; Head[u] = size;
} int N, M;
int ances[MAXN]; struct Link_Cut_Tree {
int father[MAXN];
int son[MAXN][];
int subtree[MAXN], virsize[MAXN]; void init () {
for (int i = ; i <= N; i ++)
father[i] = son[i][] = son[i][] = subtree[i] = virsize[i] = ;
}
int isroot (int p) {
return son[father[p]][] != p && son[father[p]][] != p;
}
int sonbel (int p) {
return son[father[p]][] == p;
}
void pushup (int p) {
subtree[p] = subtree[son[p][]] + subtree[son[p][]] + virsize[p] + ;
}
void rotate (int p) {
int fa = father[p], anc = father[fa];
int s = sonbel (p);
son[fa][s] = son[p][s ^ ];
if (son[fa][s])
father[son[fa][s]] = fa;
if (! isroot (fa))
son[anc][sonbel (fa)] = p;
father[p] = anc;
son[p][s ^ ] = fa, father[fa] = p;
pushup (fa), pushup (p);
}
void splay (int p) {
for (int fa = father[p]; ! isroot (p); rotate (p), fa = father[p])
if (! isroot (fa))
sonbel (p) == sonbel (fa) ? rotate (fa) : rotate (p);
}
void Access (int p) {
for (int tp = ; p; tp = p, p = father[p]) {
splay (p);
virsize[p] += subtree[son[p][]];
son[p][] = tp;
virsize[p] -= subtree[son[p][]];
pushup (p);
}
}
int findroot (int p) {
Access (p), splay (p);
while (son[p][])
p = son[p][];
splay (p);
return p;
}
void link (int p) {
int fa = ances[p];
splay (p);
father[p] = fa;
Access (fa), splay (fa);
subtree[fa] += subtree[p], virsize[fa] += subtree[p];
}
void cut (int p) {
Access (p), splay (p);
father[son[p][]] = , son[p][] = ;
pushup (p);
}
} ;
Link_Cut_Tree LCT[]; void DFS (int root, int father) {
ances[root] = father;
LCT[].link (root);
for (int i = Head[root]; i; i = Link[i].next) {
int v = Link[i].to;
if (v == father)
continue;
DFS (v, root);
}
} int Colour[MAXN]= {}; int getnum () {
int num = ;
char ch = getchar (); while (! isdigit (ch))
ch = getchar ();
while (isdigit (ch))
num = (num << ) + (num << ) + ch - '', ch = getchar (); return num;
} int main () {
N = getnum ();
for (int i = ; i <= N; i ++)
LCT[].subtree[i] = LCT[].subtree[i] = ;
for (int i = ; i < N; i ++) {
int u = getnum (), v = getnum ();
Insert (u, v), Insert (v, u);
}
DFS (, N + );
M = getnum ();
for (int Case = ; Case <= M; Case ++) {
int opt = getnum (), p = getnum ();
int col = Colour[p];
if (opt == ) {
int anc = LCT[col].findroot (p);
printf ("%d\n", LCT[col].subtree[LCT[col].son[anc][]]);
// 注意,因为有可能存在两个不连通的连通快在LCT上连通,又在Access后右节点仅包含当前链
// 故需输出右子树信息而并非减一,否则有可能会算上另一个连通块的答案
}
else if (opt == )
LCT[col].cut (p), LCT[Colour[p] ^= ].link (p);
} return ;
} /*
5
1 2
1 3
1 4
1 5
3
0 1
1 1
0 1
*/ /*
5
1 2
2 3
3 4
4 5
3
1 1
1 3
0 1
*/

SPOJ 16549 - QTREE6 - Query on a tree VI 「一种维护树上颜色连通块的操作」的更多相关文章

  1. QTREE6 - Query on a tree VI 解题报告

    QTREE6 - Query on a tree VI 题目描述 给你一棵\(n\)个点的树,编号\(1\)~\(n\).每个点可以是黑色,可以是白色.初始时所有点都是黑色.下面有两种操作请你操作给我 ...

  2. SPOJ QTREE6 Query on a tree VI 树链剖分

    题意: 给出一棵含有\(n(1 \leq n \leq 10^5)\)个节点的树,每个顶点只有两种颜色:黑色和白色. 一开始所有的点都是黑色,下面有两种共\(m(1 \leq n \leq 10^5) ...

  3. bzoj3637 CodeChef SPOJ - QTREE6 Query on a tree VI 题解

    题意: 一棵n个节点的树,节点有黑白两种颜色,初始均为白色.两种操作:1.更改一个节点的颜色;2.询问一个节点所处的颜色相同的联通块的大小. 思路: 1.每个节点记录仅考虑其子树时,假设其为黑色时所处 ...

  4. SP16549 QTREE6 - Query on a tree VI LCT维护颜色联通块

    \(\color{#0066ff}{ 题目描述 }\) 给你一棵n个点的树,编号1~n.每个点可以是黑色,可以是白色.初始时所有点都是黑色.下面有两种操作请你操作给我们看: 0 u:询问有多少个节点v ...

  5. [QTree6]Query on a tree VI

    Description: 给你一棵n个点的树,编号1~n.每个点可以是黑色,可以是白色.初始时所有点都是黑色.下面有两种操作请你操作给我们看: 0 u:询问有多少个节点v满足路径u到v上所有节点(包括 ...

  6. 洛谷SP16549 QTREE6 - Query on a tree VI(LCT)

    洛谷题目传送门 思路分析 题意就是要维护同色连通块大小.要用LCT维护子树大小就不说了,可以看看蒟蒻的LCT总结. 至于连通块如何维护,首先肯定可以想到一个很naive的做法:直接维护同色连通块,每次 ...

  7. SP16549 QTREE6 - Query on a tree VI(LCT)

    题意翻译 题目描述 给你一棵n个点的树,编号1~n.每个点可以是黑色,可以是白色.初始时所有点都是黑色.下面有两种操作请你操作给我们看: 0 u:询问有多少个节点v满足路径u到v上所有节点(包括)都拥 ...

  8. bzoj 3637: Query on a tree VI 树链剖分 && AC600

    3637: Query on a tree VI Time Limit: 8 Sec  Memory Limit: 1024 MBSubmit: 206  Solved: 38[Submit][Sta ...

  9. QTREE6&&7 - Query on a tree VI &&VII

    树上连通块 不用具体距离,只询问连通块大小或者最大权值 可以类比Qtree5的方法,但是记录东西很多,例如子树有无0/1颜色等 一个trick,两个LCT分离颜色 每个颜色在边上. 仅保留连通块顶部不 ...

随机推荐

  1. Jackson 使用

    // 序列化出来的 JSON, 不包含值为 NULL 类型字段. mapper.setSerializationInclusion(Include.NON_NULL); Jackson provide ...

  2. MT【128】不动点指路

    已知数列\(\{a_n\}\)满足\(2a_{n+1}=1-a_n^2\),且\(0<a_1<1\).求证:当\(n\geqslant 3\) 时,\(\left|\dfrac{1}{a_ ...

  3. 【刷题】BZOJ 2346 [Baltic 2011]Lamp

    Description 2255是一个傻X,他连自己家灯不亮了都不知道. 某天TZ大神路过他家,发现了这一情况, 于是TZ开始行侠仗义了. TZ发现是电路板的问题, 他打开了电路板,发现线路根本没有连 ...

  4. 【bzoj4013】 HNOI2015—实验比较

    http://www.lydsy.com/JudgeOnline/problem.php?id=4013 (题目链接) 题意 给出$n$个数的$m$个大小关系,问它们之间可以形成的单调不降的序列有多少 ...

  5. 【bzoj2002】 Hnoi2010—Bounce 弹飞绵羊

    http://www.lydsy.com/JudgeOnline/problem.php?id=2002 (题目链接) 题意 数轴上${n}$个点,每个点有一个权值${a_i}$,如果到达这个点,接下 ...

  6. c++优先队列(堆)

    1.最小堆.最大堆 priority_queue<int,vector<int>,greater<int> > f; //最小堆(后面的数逐渐greater) pr ...

  7. es6字符串新特性

    转: 字符串的扩展 修改教程 上一节 : 变量的解构赋值 下一节 : 正则的扩展 字符串的扩展 ES6 加强了对 Unicode 的支持,并且扩展了字符串对象. 字符的 Unicode 表示法 Jav ...

  8. Chapter11(关联容器)--C++Prime笔记

    1.关联容器: map关键字-值对,经常被称为关联数组 set中每个元素只有一个关键字,即只保存关键字的容器 ①允许重复的关键字的容器名字都包含multi. ②不保持关键字顺序存储的容器的名字都以但粗 ...

  9. 【Asp.net入门5-01】SportsStore:一个真实的应用程序

  10. Service Fabric基本概念:Partition/Replicas示例

    作者:张鼎松 (Dingsong Zhang) @ Microsoft 在上一节的结尾简单介绍了Service Fabric中分区Partitions和复制replicas的概念,本节主要以示例的形式 ...