[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 }

浙公网安备 33010602011771号