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

题意

有操作

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

题解

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

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

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

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

代码

  1 #include <iostream>
  2 #include <cstdio>
  3 #include <cstring>
  4
  5 using namespace std;
  6
  7 const int MAXN = 1e06 + 10;
  8 const int MAXM = 1e06 + 10;
  9
 10 struct LinkedForwardStar {
 11     int to;
 12
 13     int next;
 14 } ;
 15
 16 LinkedForwardStar Link[MAXM << 1];
 17 int Head[MAXN]= {0};
 18 int size = 0;
 19
 20 void Insert (int u, int v) {
 21     Link[++ size].to = v;
 22     Link[size].next = Head[u];
 23
 24     Head[u] = size;
 25 }
 26
 27 int N, M;
 28 int ances[MAXN];
 29
 30 struct Link_Cut_Tree {
 31     int father[MAXN];
 32     int son[MAXN][2];
 33     int subtree[MAXN], virsize[MAXN];
 34
 35     void init () {
 36         for (int i = 1; i <= N; i ++)
 37             father[i] = son[i][0] = son[i][1] = subtree[i] = virsize[i] = 0;
 38     }
 39     int isroot (int p) {
 40         return son[father[p]][0] != p && son[father[p]][1] != p;
 41     }
 42     int sonbel (int p) {
 43         return son[father[p]][1] == p;
 44     }
 45     void pushup (int p) {
 46         subtree[p] = subtree[son[p][0]] + subtree[son[p][1]] + virsize[p] + 1;
 47     }
 48     void rotate (int p) {
 49         int fa = father[p], anc = father[fa];
 50         int s = sonbel (p);
 51         son[fa][s] = son[p][s ^ 1];
 52         if (son[fa][s])
 53             father[son[fa][s]] = fa;
 54         if (! isroot (fa))
 55             son[anc][sonbel (fa)] = p;
 56         father[p] = anc;
 57         son[p][s ^ 1] = fa, father[fa] = p;
 58         pushup (fa), pushup (p);
 59     }
 60     void splay (int p) {
 61         for (int fa = father[p]; ! isroot (p); rotate (p), fa = father[p])
 62             if (! isroot (fa))
 63                 sonbel (p) == sonbel (fa) ? rotate (fa) : rotate (p);
 64     }
 65     void Access (int p) {
 66         for (int tp = 0; p; tp = p, p = father[p]) {
 67             splay (p);
 68             virsize[p] += subtree[son[p][1]];
 69             son[p][1] = tp;
 70             virsize[p] -= subtree[son[p][1]];
 71             pushup (p);
 72         }
 73     }
 74     int findroot (int p) {
 75         Access (p), splay (p);
 76         while (son[p][0])
 77             p = son[p][0];
 78         splay (p);
 79         return p;
 80     }
 81     void link (int p) {
 82         int fa = ances[p];
 83         splay (p);
 84         father[p] = fa;
 85         Access (fa), splay (fa);
 86         subtree[fa] += subtree[p], virsize[fa] += subtree[p];
 87     }
 88     void cut (int p) {
 89         Access (p), splay (p);
 90         father[son[p][0]] = 0, son[p][0] = 0;
 91         pushup (p);
 92     }
 93 } ;
 94 Link_Cut_Tree LCT[2];
 95
 96 void DFS (int root, int father) {
 97     ances[root] = father;
 98     LCT[0].link (root);
 99     for (int i = Head[root]; i; i = Link[i].next) {
100         int v = Link[i].to;
101         if (v == father)
102             continue;
103         DFS (v, root);
104     }
105 }
106
107 int Colour[MAXN]= {0};
108
109 int getnum () {
110     int num = 0;
111     char ch = getchar ();
112
113     while (! isdigit (ch))
114         ch = getchar ();
115     while (isdigit (ch))
116         num = (num << 3) + (num << 1) + ch - ‘0‘, ch = getchar ();
117
118     return num;
119 }
120
121 int main () {
122     N = getnum ();
123     for (int i = 1; i <= N; i ++)
124         LCT[0].subtree[i] = LCT[1].subtree[i] = 1;
125     for (int i = 1; i < N; i ++) {
126         int u = getnum (), v = getnum ();
127         Insert (u, v), Insert (v, u);
128     }
129     DFS (1, N + 1);
130     M = getnum ();
131     for (int Case = 1; Case <= M; Case ++) {
132         int opt = getnum (), p = getnum ();
133         int col = Colour[p];
134         if (opt == 0) {
135             int anc = LCT[col].findroot (p);
136             printf ("%d\n", LCT[col].subtree[LCT[col].son[anc][1]]);
137             // 注意,因为有可能存在两个不连通的连通快在LCT上连通,又在Access后右节点仅包含当前链
138             // 故需输出右子树信息而并非减一,否则有可能会算上另一个连通块的答案
139         }
140         else if (opt == 1)
141             LCT[col].cut (p), LCT[Colour[p] ^= 1].link (p);
142     }
143
144     return 0;
145 }
146
147 /*
148 5
149 1 2
150 1 3
151 1 4
152 1 5
153 3
154 0 1
155 1 1
156 0 1
157 */
158
159 /*
160 5
161 1 2
162 2 3
163 3 4
164 4 5
165 3
166 1 1
167 1 3
168 0 1
169 */

原文地址:https://www.cnblogs.com/Colythme/p/10218051.html

时间: 2024-10-04 16:30:49

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

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

题意: 一棵n个节点的树,节点有黑白两种颜色,初始均为白色.两种操作:1.更改一个节点的颜色;2.询问一个节点所处的颜色相同的联通块的大小. 思路: 1.每个节点记录仅考虑其子树时,假设其为黑色时所处的黑色联通块的大小和假设其为白色时所处的白色联通块的大小(树状数组维护). 2.查询时找到深度最小的.与该点颜色相同的且两点之间的点颜色均与这两点相同(两点可以重合)(不妨称它为最远祖先)的答案. 3.修改时应该修改该节点的父亲至最远祖先的父亲上的值. 4.用树链剖分和树状数组维护. 5.寻找最远祖

bzoj 3637: Query on a tree VI 树链剖分 &amp;&amp; AC600

3637: Query on a tree VI Time Limit: 8 Sec  Memory Limit: 1024 MBSubmit: 206  Solved: 38[Submit][Status][Discuss] Description You are given a tree (an acyclic undirected connected graph) with n nodes. The tree nodes are numbered from 1 to n. Each nod

SPOJ - QTREE 375 Query on a tree 树链剖分+线段树

操作1:修改第k条边权. 操作2:询问两点间最大边权. 树链剖分,然后线段树维护最大值 #include<cstdio> #include<cstring> #include<cmath> #include<iostream> #include<algorithm> #include<set> #include<map> #include<queue> #include<vector> #inclu

SPOJ QTREE 375. Query on a tree

SPOJ Problem Set (classical) 375. Query on a tree Problem code: QTREE You are given a tree (an acyclic undirected connected graph) with N nodes, and edges numbered 1, 2, 3...N-1. We will ask you to perfrom some instructions of the following form: CHA

【树链剖分模板】【SPOJ 375】 Query on a tree

375. Query on a tree Problem code: QTREE You are given a tree (an acyclic undirected connected graph) with N nodes, and edges numbered 1, 2, 3...N-1. We will ask you to perfrom some instructions of the following form: CHANGE i ti : change the cost of

SPOJ 题目913QTREE2 - Query on a tree II(Link Cut Tree 查询路径第k个点)

QTREE2 - Query on a tree II no tags You are given a tree (an undirected acyclic connected graph) with N nodes, and edges numbered 1, 2, 3...N-1. Each edge has an integer value assigned to it, representing its length. We will ask you to perfrom some i

bzoj3637: Query on a tree VI

Description You are given a tree (an acyclic undirected connected graph) with n nodes. The tree nodes are numbered from 1 to n. Each node has a color, white or black. All the nodes are black initially. We will ask you to perfrom some instructions of

SPOJ 375 QTREE - Query on a tree(树链剖分)

题目链接:http://www.spoj.com/problems/QTREE/en/ 题意:  一棵树 n 个节点,每条边上有权值,同时有两个操作: (1)更改操作:CHANGE i ti(把第 i 条边上的权值改为 ti). (2)查询操作:QUERY a b(查询 a 到 b 的路径上权值最大的边的权值). 思路(树链剖分): 看到这种区间查询的题想要用数据结构优化,提高时间效率一般会想到线段树.可是这次操作的对象并不是一组序列, 无法直接使用线段树.这时,我们可以做些转化:对树作树链剖分

spoj 375 QTREE - Query on a tree 树链剖分

题目链接 给一棵树, 每条边有权值, 两种操作, 一种是将一条边的权值改变, 一种是询问u到v路径上最大的边的权值. 树链剖分模板. #include <iostream> #include <vector> #include <cstdio> #include <cstring> #include <algorithm> #include <cmath> #include <map> #include <set&g