洛谷P5163 WD与地图
只有洛谷的毒瘤才会在毒瘤月赛里出毒瘤题......
题意:三个操作,删边,改变点权,求点x所在强连通分量内前k大点权之和。
解:狗屎毒瘤数据结构乱堆......
整体二分套(tarjan+并查集) + 线段树合并。
首先可以变成加边。
然后就是神奇操作让人难以置信......
对于每条边,我们有个时刻t使得它的两端点在同一scc内。那么如何求出这个t呢?
整体二分!...这又是怎么想到的啊......
对于一个时刻mid,我们把小于它的边提取出来缩点,如果有的边两端点在一个scc,那么它的t就不大于mid。否则大于mid。
为了保证整体二分的复杂度,我们每次操作tarjan的图不能太大。具体来说,把之前做过的区间的scc用并查集缩起来。
对于每条边,提取两端点所在scc的代表元为关键点,构出虚图(?????),然后tarjan。
之后递归左边,之后并查集缩点,之后递归右边。
所有t求出之后,再倒着跑一遍询问,按照时刻把边的两端点在并查集中合并(表示成为一个scc),并对权值线段树进行合并。
查询就是所在scc的权值线段树的前k大之和,这个好办。
注意爆int。我写了300行7k......
1 #include <cstdio> 2 #include <algorithm> 3 #include <vector> 4 #include <cstring> 5 #include <stack> 6 #include <map> 7 8 typedef long long LL; 9 const int N = 100010, M = 400010, V = 40000010; 10 11 struct Edge { 12 int nex, v; 13 }edge[M]; int tp; 14 15 struct Node { 16 int t, x, y, id; 17 }node[M], t1[M], t2[M]; 18 19 struct Ask { 20 int f, x, y; 21 LL ans; 22 }ask[M]; 23 24 std::vector<Node> v[M]; 25 std::stack<int> S; 26 std::map<int, int> mp[N]; 27 int e[N], fr[N], stk[N], top, dfn[N], low[N], use[N], X[N + M], xx, rt[N], sum[V], ls[V], rs[V], val[N]; 28 int Time, scc_cnt, num, n, m, q, tot; 29 LL Val[V]; 30 31 inline void add(int x, int y) { 32 tp++; 33 edge[tp].v = y; 34 edge[tp].nex = e[x]; 35 e[x] = tp; 36 return; 37 } 38 39 namespace ufs { 40 int fa[N]; 41 int find(int x) { 42 if(fa[x] == x) { 43 return x; 44 } 45 return fa[x] = find(fa[x]); 46 } 47 inline void merge(int x, int y) { 48 fa[find(x)] = find(y); 49 return; 50 } 51 inline void clear() { 52 for(int i = 1; i <= n; i++) { 53 fa[i] = i; 54 } 55 return; 56 } 57 } 58 59 void tarjan(int x) { 60 low[x] = dfn[x] = ++num; 61 S.push(x); 62 //printf("tarjan %d \n", x); 63 for(int i = e[x]; i; i = edge[i].nex) { 64 int y = edge[i].v; 65 if(!dfn[y]) { 66 tarjan(y); 67 low[x] = std::min(low[x], low[y]); 68 } 69 else if(!fr[y]) { // find 70 low[x] = std::min(low[x], dfn[y]); 71 } 72 } 73 if(low[x] == dfn[x]) { 74 //printf("getscc \n"); 75 ++scc_cnt; 76 int y; 77 do { 78 y = S.top(); 79 //printf("%d ", y); 80 S.pop(); 81 fr[y] = scc_cnt; 82 //ufs::merge(x, y); 83 } while(y != x); 84 //puts(""); 85 } 86 return; 87 } 88 89 inline void TAR() { 90 scc_cnt = num = 0; 91 for(int i = 1; i <= top; i++) { 92 if(!dfn[stk[i]]) { 93 tarjan(stk[i]); 94 } 95 } 96 return; 97 } 98 99 inline void link(int x, int y) { 100 x = ufs::find(x); y = ufs::find(y); 101 if(use[x] != Time) { 102 use[x] = Time; 103 dfn[x] = fr[x] = e[x] = 0; 104 stk[++top] = x; 105 } 106 if(use[y] != Time) { 107 use[y] = Time; 108 dfn[y] = fr[y] = e[y] = 0; 109 stk[++top] = y; 110 } 111 add(x, y); // self-circle is OK 112 return; 113 } 114 115 inline void solve(int L, int R, int l, int r) { 116 if(R < L) { 117 return; 118 } 119 //printf("solve %d %d %d %d \n", L, R, l, r); 120 if(l == r) { 121 for(int i = L; i <= R; i++) { 122 v[r].push_back(node[i]); 123 } 124 return; 125 } 126 int mid = (l + r) >> 1; 127 ++Time; top = tp = 0; 128 for(int i = L; i <= R; i++) { 129 if(node[i].t <= mid) { 130 link(node[i].x, node[i].y); 131 } 132 } 133 //int ufs_t = ufs::top; 134 TAR(); 135 int top1 = 0, top2 = 0; 136 for(int i = L; i <= R; i++) { 137 int x = ufs::find(node[i].x), y = ufs::find(node[i].y); 138 if(node[i].t <= mid && fr[x] == fr[y]) { 139 t1[++top1] = node[i]; 140 } 141 else { 142 t2[++top2] = node[i]; 143 } 144 } 145 memcpy(node + L, t1 + 1, top1 * sizeof(Node)); 146 memcpy(node + L + top1, t2 + 1, top2 * sizeof(Node)); 147 solve(L, L + top1 - 1, l, mid); 148 for(int i = L; i < L + top1; i++) { 149 int x = ufs::find(node[i].x); 150 int y = ufs::find(node[i].y); 151 ufs::merge(x, y); 152 } 153 solve(L + top1, R, mid + 1, r); 154 return; 155 } 156 157 int merge(int x, int y) { 158 if(!x || !y || x == y) { 159 return x | y; 160 } 161 int o = ++tot; 162 sum[o] = sum[x] + sum[y]; 163 Val[o] = Val[x] + Val[y]; 164 ls[o] = merge(ls[x], ls[y]); 165 rs[o] = merge(rs[x], rs[y]); 166 return o; 167 } 168 169 void add(int p, int v, int l, int r, int &o) { 170 //printf("add : %d %d %d %d \n", p, v, l, r); 171 if(!o) { 172 o = ++tot; 173 } 174 if(l == r) { 175 sum[o] += v; 176 Val[o] += v * X[r]; 177 return; 178 } 179 int mid = (l + r) >> 1; 180 if(p <= mid) { 181 add(p, v, l, mid, ls[o]); 182 } 183 else { 184 add(p, v, mid + 1, r, rs[o]); 185 } 186 sum[o] = sum[ls[o]] + sum[rs[o]]; 187 Val[o] = Val[ls[o]] + Val[rs[o]]; 188 return; 189 } 190 191 LL query(int k, int l, int r, int o) { 192 //printf("query %d [%d %d] \n", k, l, r); 193 if(!o) { 194 return 0; 195 } 196 if(l == r) { 197 return 1ll * std::min(k, sum[o]) * X[r]; 198 } 199 int mid = (l + r) >> 1; 200 if(sum[rs[o]] >= k) { 201 return query(k, mid + 1, r, rs[o]); 202 } 203 else { 204 return Val[rs[o]] + query(k - sum[rs[o]], l, mid, ls[o]); 205 } 206 } 207 208 int main() { 209 210 scanf("%d%d%d", &n, &m, &q); 211 ufs::clear(); 212 for(int i = 1; i <= n; i++) { 213 scanf("%d", &val[i]); 214 X[++xx] = val[i]; 215 } 216 for(int i = 1; i <= m; i++) { 217 scanf("%d%d", &node[i].x, &node[i].y); 218 mp[node[i].x][node[i].y] = i; 219 node[i].id = i; 220 } 221 for(int i = 1; i <= q; i++) { 222 scanf("%d%d%d", &ask[i].f, &ask[i].x, &ask[i].y); 223 if(ask[i].f == 2) { 224 ask[i].y += val[ask[i].x]; 225 X[++xx] = ask[i].y; 226 std::swap(val[ask[i].x], ask[i].y); 227 } 228 } 229 std::sort(X + 1, X + xx + 1); 230 xx = std::unique(X + 1, X + xx + 1) - X - 1; 231 for(int i = 1; i <= n; i++) { 232 val[i] = std::lower_bound(X + 1, X + xx + 1, val[i]) - X; 233 } 234 for(int i = 1; i <= q; i++) { 235 if(ask[i].f == 2) { 236 ask[i].y = std::lower_bound(X + 1, X + xx + 1, ask[i].y) - X; 237 } 238 } 239 std::reverse(ask + 1, ask + q + 1); 240 for(int i = 1; i <= q; i++) { 241 if(ask[i].f == 1) { 242 int t = mp[ask[i].x][ask[i].y]; 243 node[t].t = i; 244 } 245 } 246 247 solve(1, m, 1, q + 1); 248 //printf("--------------------------------\n"); 249 ufs::clear(); 250 for(int i = 1; i <= n; i++) { 251 add(val[i], 1, 1, xx, rt[i]); 252 } 253 for(int i = 1; i <= q; i++) { 254 //printf("i = %d \n", i); 255 for(int j = 0; j < v[i].size(); j++) { 256 //printf(" > edge = %d %d \n", v[i][j].x, v[i][j].y); 257 int x = ufs::find(v[i][j].x), y = ufs::find(v[i][j].y); 258 ufs::merge(x, y); 259 int t = ufs::find(x); 260 rt[t] = merge(rt[x], rt[y]); 261 //printf("%d = merge %d %d \n", t, x, y); 262 } 263 if(ask[i].f == 3) { 264 int t = ufs::find(ask[i].x); 265 ask[i].ans = query(ask[i].y, 1, xx, rt[t]); 266 } 267 else if(ask[i].f == 2) { 268 int t = ufs::find(ask[i].x); 269 //printf("change %d : %d -> %d \n", ask[i].x, X[val[ask[i].x]], X[ask[i].y]); 270 add(val[ask[i].x], -1, 1, xx, rt[t]); 271 add(ask[i].y, 1, 1, xx, rt[t]); 272 val[ask[i].x] = ask[i].y; 273 } 274 } 275 for(int i = q; i >= 1; i--) { 276 if(ask[i].f == 3) { 277 printf("%lld\n", ask[i].ans); 278 } 279 } 280 return 0; 281 }
对拍真是个好东西。