题意:给定图,每条边都有一段存在时间。求每段时间的最小生成树。
解:动态MST什么毒瘤...洛谷上还是蓝题...
线段树分治 + lct维护最小生成树。
对时间开线段树,每条边的存在时间在上面会对应到logn个区间。
我们先把这些边加到线段树对应节点上,但是不在lct上面加。最后扫一遍线段树。
扫到一个节点的时候把当前节点上的边加入lct,同时记录做了什么操作。回溯的时候还原操作。
最小生成树的权值不用lct维护子树和,直接用一个变量,加边删边的时候跟着修改即可。
这样复杂度就是nlog2n的...虽然常数上天了。
注意一下就是,回溯操作的时候顺序必须严格倒序。否则会出现一些情况导致re。
1 #include <cstdio> 2 #include <algorithm> 3 #include <vector> 4 5 typedef long long LL; 6 const int N = 500010, lm = 32766; 7 8 int fa[N], s[N][2], large[N], p[N], top; 9 bool rev[N]; 10 LL val[N]; 11 12 inline void pushup(int x) { 13 large[x] = x; 14 if(s[x][0] && val[large[x]] < val[large[s[x][0]]]) { 15 large[x] = large[s[x][0]]; 16 } 17 if(s[x][1] && val[large[x]] < val[large[s[x][1]]]) { 18 large[x] = large[s[x][1]]; 19 } 20 return; 21 } 22 23 inline void pushdown(int x) { 24 if(rev[x]) { 25 std::swap(s[x][0], s[x][1]); 26 if(s[x][0]) { 27 rev[s[x][0]] ^= 1; 28 } 29 if(s[x][1]) { 30 rev[s[x][1]] ^= 1; 31 } 32 rev[x] = 0; 33 } 34 return; 35 } 36 37 inline bool no_root(int x) { 38 return (s[fa[x]][0] == x) || (s[fa[x]][1] == x); 39 } 40 41 inline void rotate(int x) { 42 int y = fa[x]; 43 int z = fa[y]; 44 bool f = (s[y][1] == x); 45 46 fa[x] = z; 47 if(no_root(y)) { 48 s[z][s[z][1] == y] = x; 49 } 50 s[y][f] = s[x][!f]; 51 if(s[x][!f]) { 52 fa[s[x][!f]] = y; 53 } 54 s[x][!f] = y; 55 fa[y] = x; 56 57 pushup(y); 58 return; 59 } 60 61 inline void splay(int x) { 62 int y = x; 63 p[++top] = y; 64 while(no_root(y)) { 65 y = fa[y]; 66 p[++top] = y; 67 } 68 while(top) { 69 pushdown(p[top]); 70 top--; 71 } 72 73 y = fa[x]; 74 int z = fa[y]; 75 while(no_root(x)) { 76 if(no_root(y)) { 77 (s[z][1] == y) ^ (s[y][1] == x) ? 78 rotate(x) : rotate(y); 79 } 80 rotate(x); 81 y = fa[x]; 82 z = fa[y]; 83 } 84 pushup(x); 85 return; 86 } 87 88 inline void access(int x) { 89 int y = 0; 90 while(x) { 91 splay(x); 92 s[x][1] = y; 93 pushup(x); 94 y = x; 95 //printf("fa %d = %d ", x, fa[x]); 96 x = fa[x]; 97 } 98 return; 99 } 100 101 inline void make_root(int x) { 102 access(x); 103 splay(x); 104 rev[x] = 1; 105 return; 106 } 107 108 inline int find_root(int x) { 109 access(x); 110 splay(x); 111 while(s[x][0]) { 112 x = s[x][0]; 113 pushdown(x); 114 } 115 return x; 116 } 117 118 inline void link(int x, int y) { 119 //printf("link %d %d ", x, y); 120 make_root(x); 121 fa[x] = y; 122 return; 123 } 124 125 inline void cut(int x, int y) { 126 //printf("cut %d %d ", x, y); 127 make_root(x); 128 access(y); 129 splay(y); 130 s[y][0] = fa[x] = 0; 131 pushup(y); 132 return; 133 } 134 135 inline int getMax(int x, int y) { 136 make_root(x); 137 access(y); 138 splay(y); 139 return large[y]; 140 } 141 // lct OVER 142 143 struct Edge { 144 int u, v; 145 LL val; 146 Edge(int x = 0, int y = 0, LL z = 0) { 147 u = x; 148 v = y; 149 val = z; 150 } 151 }edge[N]; 152 153 struct Node { 154 bool f; // 0 link 1 cut 155 int x; 156 Node(bool F = 0, int X = 0) { 157 f = F; 158 x = X; 159 } 160 }; 161 162 std::vector<int> id[N]; 163 std::vector<Node> v[N]; 164 int n; 165 LL Sum; 166 167 void add(int L, int R, int v, int l, int r, int o) { 168 if(L <= l && r <= R) { 169 id[o].push_back(v); 170 return; 171 } 172 int mid = (l + r) >> 1; 173 if(L <= mid) { 174 add(L, R, v, l, mid, o << 1); 175 } 176 if(mid < R) { 177 add(L, R, v, mid + 1, r, o << 1 | 1); 178 } 179 return; 180 } 181 182 void solve(int l, int r, int o) { 183 //printf("solve %d %d %d ", l, r, o); 184 for(int i = 0; i < id[o].size(); i++) { 185 int t = id[o][i]; 186 int x = edge[t].u, y = edge[t].v; 187 int p = getMax(x, y); 188 if(val[p] < edge[t].val) { 189 continue; 190 } 191 cut(edge[p].u, p); 192 cut(edge[p].v, p); 193 link(x, t); 194 link(y, t); 195 v[o].push_back(Node(1, p)); 196 v[o].push_back(Node(0, t)); // pay attention! this must be behind 197 Sum -= val[p]; 198 Sum += val[t]; 199 //printf(" > push %d %d ", t, p); 200 } 201 if(l == r) { 202 printf("%lld ", Sum + 1); 203 } 204 else { 205 int mid = (l + r) >> 1; 206 solve(l, mid, o << 1); 207 solve(mid + 1, r, o << 1 | 1); 208 } 209 //printf(" -- solve %d %d %d ", l, r, o); 210 for(int i = v[o].size() - 1; i >= 0; i--) { // this must be sleep 211 int t = v[o][i].x; 212 if(v[o][i].f) { 213 link(edge[t].u, t); 214 link(edge[t].v, t); 215 Sum += val[t]; 216 } 217 else { 218 cut(edge[t].u, t); 219 cut(edge[t].v, t); 220 Sum -= val[t]; 221 } 222 //printf(" -- > pop %d ", t); 223 } 224 v[o].clear(); 225 return; 226 } 227 228 int main() { 229 230 scanf("%d", &n); 231 LL z; 232 for(int i = 1, x, y; i < n; i++) { 233 scanf("%d%d%lld", &x, &y, &z); 234 val[n + i] = z; 235 link(x, n + i); 236 link(n + i, y); 237 edge[n + i].u = x; 238 edge[n + i].v = y; 239 edge[n + i].val = z; 240 Sum += z; 241 } 242 int m; 243 scanf("%d", &m); 244 for(int i = 1, l, r; i <= m; i++) { 245 int t = 2 * n + i; 246 scanf("%d%d%lld%d%d", &edge[t].u, &edge[t].v, &edge[t].val, &l, &r); 247 val[t] = edge[t].val; 248 add(l, r, t, 1, lm, 1); 249 } 250 251 solve(1, lm, 1); 252 253 return 0; 254 }