题意

有操作

$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. Smallest Minimum Cut HDU - 6214(最小割集)

    Smallest Minimum Cut Time Limit: 2000/2000 MS (Java/Others)    Memory Limit: 65535/32768 K (Java/Oth ...

  2. [洛谷P3175][HAOI2015]按位或

    题目大意:刚开始有一个数$x=0$,每秒钟有一个数$y\in[0,2^n)(n\leqslant20)$按一定概率随机出现,数$i$的概率为$p_i$,保证$\sum\limits_{i=0}^{2^ ...

  3. 注册系统所有的dll文件.bat

    @echo off echo 运行后,能重新注册系统所有的dll文件, echo 能解决内存读写错误的问题 pause echo on for %%1 in (%windir%/system32/*. ...

  4. 【BZOJ3622】已经没有什么好害怕的了(动态规划,容斥)

    [BZOJ3622]已经没有什么好害怕的了(动态规划,容斥) 题面 BZOJ 题解 很明显的,这类问题是要从至少变成恰好的过程,直接容斥即可. 首先我们要求的是(糖果>药片)=(药片>糖果 ...

  5. Shell中[]里面的条件判断

    1.字符串判断 str1 = str2 当两个串有相同内容.长度时为真 str1 != str2 当串str1和str2不等时为真 -n str1 当串的长度大于0时为真(串非空) -z str1 当 ...

  6. 关于Powershell对抗安全软件(转)

    Windows PowerShell的强大,并且内置,在渗透过程中,也让渗透变得更加有趣.而安全软件的对抗查杀也逐渐开始针对powershell的一切行为.在https://technet.micro ...

  7. POJ.1986 Distance Queries ( LCA 倍增 )

    POJ.1986 Distance Queries ( LCA 倍增 ) 题意分析 给出一个N个点,M条边的信息(u,v,w),表示树上u-v有一条边,边权为w,接下来有k个询问,每个询问为(a,b) ...

  8. substring()方法到底做了什么?不同版本的JDK中是否有区别?为什么?

      该文章是图说Java系列文章中的一篇 substring(int beginIndex, int endIndex)方法在jdk 6和jdk 7中的实现是不同的.了解他们的区别可以帮助你更好的使用 ...

  9. Docker应用四:搭建docker镜像仓库(包括自生成https证书、登陆认证)

    利用docker官网提供的registry镜像创建私有仓库 一.首先从docker官网拉取registry镜像: docker pull registry 二.然后运行该镜像: docker run ...

  10. Go_20: Golang 中 time 包的使用

    time包中包括两类时间:时间点(某一时刻)和时常(某一段时间) 1. 时间常量(时间格式化) const ( ANSIC = "Mon Jan _2 15:04:05 2006" ...