码迷,mamicode.com
首页 > 其他好文 > 详细

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

时间:2019-01-04 10:30:44      阅读:264      评论:0      收藏:0      [点我收藏+]

标签:link   连通   push   ==   tin   bsp   包括   std   code   

题意

有操作

$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 */

 

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

标签:link   连通   push   ==   tin   bsp   包括   std   code   

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

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!