[APIO 2019]桥梁[分块][可撤销并查集]

桥梁

题面

考虑暴力。有一种可行方法是每次询问操作遍历边,通过加入并查集并获得并查集大小的方法完成,预计得分 13 pts

再考虑暴力。若没有修改操作,很容易想到把询问排序再把边排序后一个一个添加边来解决,那么如果有修改呢?

思路同上,将边按有无修改分开,无修改的同上,遍历询问操作,每次询问操作遍历所有修改操作,若修改操作比询问操作出现早则修改,再类似于第一种暴力地加并查集,一次询问操作后都撤销掉并查集,预计得分 13 pts

两种方法的速度分别取决于修改量和询问量,考虑将两种方法合并到一块,使各自要操作的部分的修改量或询问量都不太高

考虑操作分块

分成若干个大小为 S 的块

对于块内操作离线后照抄暴力2

处理完一个块后用暴力1 的方法直接修改边权

复杂度有点毒瘤没算

Code:

  1 #include <ctime>
  2 #include <cmath>
  3 #include <cstdio>
  4 #include <cstring>
  5 #include <cstdlib>
  6 #include <iostream>
  7 #include <algorithm>
  8 #include <vector>
  9 #include <queue>
 10 #include <cmath>
 11 #define inf 100010
 12 #define INF 0x7fffffff
 13 #define ll long long
 14 
 15 // const unsigned int size = 500;
 16 unsigned int size = 0;
 17 
 18 namespace io {
 19     const int SIZE = (1 << 21) + 1;
 20     char ibuf[SIZE], *iS, *iT, obuf[SIZE], *oS = obuf, *oT = oS + SIZE - 1, c, qu[55]; int f, qr;
 21     
 22     #define gc() (iS == iT ? (iT = (iS = ibuf) + fread (ibuf, 1, SIZE, stdin), (iS == iT ? EOF : *iS ++)) : *iS ++)
 23     
 24     inline void flush () {
 25         fwrite (obuf, 1, oS - obuf, stdout);
 26         oS = obuf;
 27     }
 28     
 29     inline void putc (char x) {
 30         *oS ++ = x;
 31         if (oS == oT) flush ();
 32     }
 33     
 34     template <class I>
 35     inline void read (I &x) {
 36         for (f = 1, c = gc(); c < '0' || c > '9'; c = gc()) if (c == '-') f = -1;
 37         for (x = 0; c <= '9' && c >= '0'; c = gc()) x = x * 10 + (c & 15); 
 38         x *= f;
 39     }
 40     
 41     template <class I>
 42     inline void print (I x) {
 43         if (!x) putc ('0'); 
 44         if (x < 0) putc ('-'), x = -x;
 45         while (x) qu[++ qr] = x % 10 + '0',  x /= 10;
 46         while (qr) putc (qu[qr --]);
 47     }
 48     
 49     struct Flusher_ {~Flusher_(){flush();}}io_flusher_;
 50 }
 51 using io :: read; using io :: putc; using io :: print;
 52 template <class I>
 53 inline void read(I &a, I &b) {read(a); read(b);}
 54 template <class I>
 55 inline void read(I &a, I &b, I &c) {read(a); read(b); read(c);}
 56 
 57 struct edge {
 58     int from;
 59     int to;
 60     int val;
 61     int id;
 62     inline void made(int f, int t, int v, int i) {
 63         from = f, to = t, val = v, id = i;
 64     }
 65 };
 66 edge e[inf];
 67 int indexEdge;
 68 
 69 inline void connect(int from, int to, int val, int id){
 70     ++indexEdge;
 71     e[indexEdge].made(from, to, val, id);
 72     return;
 73 }
 74 
 75 struct opera {
 76     int id;
 77     int opt;
 78     int pos;
 79     int dis;
 80     inline void made(int i, int t, int p, int d) {
 81         id = i, opt = t, pos = p, dis = d;
 82     }
 83 };
 84 std::vector <opera> Opt;
 85 
 86 int n, m, q;
 87 
 88 int ans[inf];
 89 
 90 namespace dsu { // dsu with back()
 91     struct Node {
 92         int first;
 93         int second;
 94     };
 95 
 96     int fa[inf], sz[inf];
 97     std::vector <Node> stack;
 98 
 99     inline void init(int n) {
100         stack.clear();
101         for(int i = 1; i <= n; i++) fa[i] = i, sz[i] = 1;
102         return;
103     }
104     
105     int find(int f) {
106         return fa[f] == f ? f : find(fa[f]);
107     }
108 
109     inline void Union(int a, int b) {
110         int af = find(a), bf = find(b);
111         if(af == bf) return;
112         if(sz[af] < sz[bf]) std::swap(af, bf);
113         sz[af] += sz[bf];
114         fa[bf] = af;
115         stack.push_back((Node){af, bf});
116         return;
117     }
118 
119     inline void back(unsigned int goal) {
120         while(stack.size() > goal) {
121             int u = stack.back().first, v = stack.back().second;
122             fa[v] = v;
123             sz[u] -= sz[v];
124             stack.pop_back();
125         }
126         return;
127     }
128 }
129 
130 inline bool cmpEdge(const edge& a, const edge& b) {
131     return (a.val == b.val) ? (a.id < b.id) : (a.val > b.val);
132 }
133 
134 inline bool cmpOpera(const opera& a, const opera& b) {
135     return a.dis > b.dis;
136 }
137 
138 bool repair[inf]; // Does this edge need to repair
139 int reid[inf];
140 int val[inf]; // the val of edges when querying
141 std::vector <opera> opt1, opt2;
142 std::vector <edge> tmp1, tmp2;
143 
144 inline void solve() {
145     std::fill(repair, repair + 1 + m, 0);
146     dsu::init(n);
147     opt1.clear(), opt2.clear();
148 
149     for(std::vector <opera> :: iterator it = Opt.begin(); it != Opt.end(); it++) {
150         if(it->opt == 1) opt1.push_back(*it), repair[it->pos] = 1;
151         else opt2.push_back(*it);
152     }
153     
154     std::sort(opt2.begin(), opt2.end(), cmpOpera);
155 
156     for(int i = 1; i <= m; i++) reid[e[i].id] = i;
157 
158     int j = 1;
159     for(std::vector <opera> :: iterator it = opt2.begin(); it != opt2.end(); it++) {
160         // dsu the edges that will be never changed
161         while(j <= m && e[j].val >= it->dis) {
162             if(repair[e[j].id] == 0) dsu::Union(e[j].to, e[j].from);
163             ++j;
164         }
165         int now = dsu::stack.size();
166         // copy the init val of each edge
167         for(std::vector <opera> :: iterator iter = opt1.begin(); iter != opt1.end(); iter++) {
168             val[iter->pos] = e[reid[iter->pos]].val;
169         }
170         // execute the changes that are before this query
171         for(std::vector <opera> :: iterator iter = opt1.begin(); iter != opt1.end(); iter++) {
172             if(iter->id < it->id) val[iter->pos] = iter->dis;
173         }
174         for(std::vector <opera> :: iterator iter = opt1.begin(); iter != opt1.end(); iter++) {
175             if(val[iter->pos] >= it->dis)
176                 dsu::Union(e[reid[iter->pos]].from, e[reid[iter->pos]].to);
177         }
178         ans[it->id] = dsu::sz[dsu::find(it->pos)];
179         dsu::back(now);
180     }
181     // execute the changes in this block
182     for(std::vector <opera> :: iterator iter = opt1.begin(); iter != opt1.end(); iter++) {
183         e[reid[iter->pos]].val = iter->dis;
184     }
185 
186     tmp1.clear(), tmp2.clear();
187     for(int i = 1; i <= m; i++) {
188         if(repair[e[i].id]) tmp1.push_back(e[i]);
189         else tmp2.push_back(e[i]);
190     }
191     
192     std::sort(tmp1.begin(), tmp1.end(), cmpEdge);
193     std::merge(tmp1.begin(), tmp1.end(), tmp2.begin(), tmp2.end(), e + 1, cmpEdge);
194     return;
195 }
196 
197 inline void setting();
198 
199 int main () {
200     setting();
201     read(n, m);
202     size = 500;
203     // size = sqrt(1.0 * n * log2(1.0 * n));
204     for(int i = 1; i <= m; i++) {
205         int u, v, w;
206         read(u, v, w);
207         connect(u, v, w, i);
208     }
209     std::sort(e + 1, e + 1 + m, cmpEdge);
210     read(q);
211     for(int i = 1; i <= q; i++) {
212         int opt, a, b;
213         read(opt, a, b);
214         Opt.push_back((opera){i, opt, a, b});
215         if(Opt.size() == size) {
216             solve();
217             Opt.clear();
218         }
219     }
220     if(Opt.size()) solve();
221     for(int i = 1; i <= q; i++) {
222         if(ans[i]) printf("%d\n", ans[i]);
223     }
224     return 0;
225 }
226 
227 inline void setting(){
228 #ifndef ONLINE_JUDGE
229     freopen("_test.in", "r", stdin);
230     freopen("_test.out", "w", stdout);
231 #endif
232     return;
233 }
posted @ 2020-07-30 17:13  Chiaro  阅读(171)  评论(0)    收藏  举报