洛谷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 }
AC代码

对拍真是个好东西。

posted @ 2019-02-19 20:58  huyufeifei  阅读(232)  评论(0编辑  收藏  举报
试着放一个广告栏(虽然没有一分钱广告费)

『Flyable Heart 応援中!』 HHG 高苗京铃 闪十PSS 双六 電動伝奇堂 章鱼罐头制作组 はきか 祝姬 星降夜