BZOJ 2959 - 长跑

题意

每个点有各自的权值,要求维护操作:动态加边、动态修改权值、询问在每个点只能经过一次的情况下两点间路程中的最大权值和

题解

首先对于一个静态的图,将其缩点,可以得到一棵树,那么两点间询问的答案即为它们之间经过的 $BCC$ 的权值和

支持动态加边,就需要用到 $LCT$ 去维护 $BCC$

如果两个点所在 $BCC$ 在不同树上,那么直接连边即可;反之,则说明形成了环,就暴力将这条链拖出来,用选定一个标准节点,用并查集将链上其它节点连到标准节点上,容易证明,这样的复杂度是均摊 $O (\log n)$ 的

查询即修改容易实现,不加赘述

注意,此题没有删边,所以 $findroot$ 可用另一个并查集代替,不然会 $T$

代码

  1 #include <iostream>
  2 #include <cstdio>
  3 #include <cstring>
  4 #include <map>
  5 
  6 using namespace std;
  7 
  8 typedef long long LL;
  9 
 10 const int MAXN = 15e04 + 10;
 11 
 12 int ances[MAXN];
 13 int find (int p) {
 14     return p == ances[p] ? p : ances[p] = find (ances[p]);
 15 }
 16 int lctanc[MAXN];
 17 int lctfind (int p) {
 18     return p == lctanc[p] ? p : lctanc[p] = lctfind (lctanc[p]);
 19 }
 20 
 21 LL realval[MAXN];
 22 int father[MAXN]= {0};
 23 int son[MAXN][2]= {0};
 24 LL Sum[MAXN]= {0}, value[MAXN]= {0};
 25 int revtag[MAXN]= {0};
 26 
 27 int isroot (int p) {
 28     return son[father[p]][0] != p && son[father[p]][1] != p;
 29 }
 30 int sonbel (int p) {
 31     return son[father[p]][1] == p;
 32 }
 33 void reverse (int p) {
 34     if (! p)
 35         return ;
 36     swap (son[p][0], son[p][1]);
 37     revtag[p] ^= 1;
 38 }
 39 void pushup (int p) {
 40     Sum[p] = Sum[son[p][0]] + Sum[son[p][1]] + value[p];
 41 }
 42 void pushdown (int p) {
 43     if (revtag[p]) {
 44         reverse (son[p][0]), reverse (son[p][1]);
 45         revtag[p] = 0;
 46     }
 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 int Stack[MAXN];
 61 int top = 0;
 62 void splay (int p) {
 63     top = 0, Stack[++ top] = p;
 64     for (int nd = p; ! isroot (nd); nd = father[nd])
 65         Stack[++ top] = father[nd];
 66     while (top > 0)
 67         pushdown (Stack[top]), top --;
 68     for (int fa = father[p]; ! isroot (p); rotate (p), fa = father[p])
 69         if (! isroot (fa))
 70             sonbel (p) == sonbel (fa) ? rotate (fa) : rotate (p);
 71 }
 72 void Access (int p) {
 73     for (int tp = 0; p; tp = p, p = father[tp] = find (father[p])) // 注意因为有并查集,所以也要同时更新father[tp]
 74         splay (p), son[p][1] = tp, pushup (p);
 75 }
 76 void Makeroot (int p) {
 77     Access (p), splay (p), reverse (p);
 78 }
 79 void Split (int x, int y) {
 80     Makeroot (x);
 81     Access (y), splay (y);
 82 }
 83 void link (int x, int y) {
 84     Makeroot (x);
 85     father[x] = y;
 86     int fx = lctfind (x), fy = lctfind (y);
 87     lctanc[fx] = fy;
 88 }
 89 
 90 void merge (int p, int root) { // 暴力合并
 91     if (! p)
 92         return ;
 93     if (p != root)
 94         ances[p] = root, value[root] += value[p];
 95     merge (son[p][0], root), merge (son[p][1], root);
 96 }
 97 void Add (int x, int y) {
 98     int fx = find (x), fy = find (y);
 99     if (fx == fy)
100         return ;
101     if (lctfind (fx) != lctfind (fy)) {
102         link (fx, fy);
103         return ;
104     }
105     Split (fx, fy);
106     merge (fy, fy);
107     son[fy][0] = son[fy][1] = 0;
108     pushup (fy);
109 }
110 void Modify (int x, int val) {
111     int fx = find (x);
112     splay (fx);
113     value[fx] -= realval[x] - val, realval[x] = val;
114     pushup (fx);
115 }
116 LL Query (int x, int y) {
117     int fx = find (x), fy = find (y);
118     if (lctfind (fx) != lctfind (fy))
119         return - 1;
120     Split (fx, fy);
121     return Sum[fy];
122 }
123 
124 int N, M;
125 
126 int getnum () {
127     int num = 0;
128     char ch = getchar ();
129     int isneg = 0;
130 
131     while (! isdigit (ch)) {
132         if (ch == '-')
133             isneg = 1;
134         ch = getchar ();
135     }
136     while (isdigit (ch))
137         num = (num << 3) + (num << 1) + ch - '0', ch = getchar ();
138 
139     return isneg ? - num : num;
140 }
141 
142 int answer[MAXN];
143 int cnt = 0;
144 int main () {
145     int N = getnum (), M = getnum ();
146     for (int i = 1; i <= N; i ++)
147         Sum[i] = value[i] = realval[i] = getnum (), lctanc[i] = ances[i] = i;
148     for (int i = 1; i <= M; i ++) {
149         int type = getnum ();
150         int x = getnum (), y = getnum ();
151         if (type == 1)
152             Add (x, y);
153         else if (type == 2)
154             Modify (x, y);
155         else if (type == 3)
156             printf ("%lld\n", Query (x, y));
157     }
158 
159     return 0;
160 }
161 
162 /*
163 9 31
164 10 20 30 40 50 60 70 80 90
165 3 1 2
166 1 1 3
167 1 1 2
168 1 8 9
169 1 2 4
170 1 2 5
171 1 4 6
172 1 4 7
173 3 1 8
174 3 8 8
175 1 8 9
176 3 8 8
177 3 7 5
178 3 7 3
179 1 4 1
180 3 7 5
181 3 7 3
182 1 5 7
183 3 6 5
184 3 3 6
185 1 2 4
186 1 5 5
187 3 3 6
188 2 8 180
189 3 8 8
190 2 9 190
191 3 9 9
192 2 5 150
193 3 3 6
194 2 1 210
195 3 3 6
196 */

 

posted @ 2018-12-27 21:55  Colythme  阅读(191)  评论(0编辑  收藏  举报