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