(树上莫队)HDU - 5799 This world need more Zhu
Posted tak_fate
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了(树上莫队)HDU - 5799 This world need more Zhu相关的知识,希望对你有一定的参考价值。
题意:
两种询问:
1、询问以u为根的子树中出现的a次的数的和与出现b次的数的和的gcd。
2、询问u到v的树链中出现的a次的数的和与出现b次的数的和的gcd。
有点绕。。
分析:
因为自己不会树上莫队,所以学习了一波。
但是对于子树我还是有所经验,可以转成dfs序来做,之前有做过类似的题,比如这题。
然而对于树链有点懵逼,虽然我觉得也能用dfs序做,不过看大佬们的dfs序做的树链查询,也有点懵,感觉写起来很麻烦。
貌似是修改了dfs序,回溯的时候不再只是和进入时相同的序,而是独立的序。
还是感觉麻烦。。后来发现一个基于树分块的树上莫队,感觉很强。代码显然没有前者复杂。所以就用了它。
第一种询问其实有nlogn的做法,跟上面的之前做过的 dfs序题是同一题。
但是这里写的代码好长啊。。虽然很挫。。
代码:
1 #include <iostream> 2 #include <cstdio> 3 #include <algorithm> 4 #include <cmath> 5 #include <cstring> 6 #include <set> 7 #include <vector> 8 #include <queue> 9 #include <map> 10 #include <list> 11 #include <bitset> 12 #include <string> 13 #include <cctype> 14 #include <cstdlib> 15 16 using namespace std; 17 18 typedef long long ll; 19 typedef unsigned long long ull; 20 #define inf (0x3f3f3f3f) 21 #define lnf (0x3f3f3f3f3f3f3f3f) 22 #define eps (1e-8) 23 int sgn(double a) { 24 return a < -eps ? -1 : a < eps ? 0 : 1; 25 } 26 27 const int maxn = 100010; 28 29 int t; 30 struct Q { 31 int u, v, a, b; 32 int l, r; 33 int index; 34 }; 35 36 37 int col[maxn]; 38 int cnt[maxn]; 39 ll cs[maxn]; 40 ll ans[maxn]; 41 const int bk = 316; 42 43 const int DEG = 20; 44 vector<Q> query[3]; 45 vector<int> g[maxn]; 46 47 int n, q; 48 int a[maxn], b[maxn]; 49 50 inline bool scan_d(int &num) { 51 char in; 52 bool IsN = false; 53 in = getchar(); 54 if(in == EOF) return false; 55 while(in != \'-\' && (in < \'0\' || in > \'9\')) in = getchar(); 56 if(in == \'-\') { 57 IsN = true; 58 num = 0; 59 } else num = in - \'0\'; 60 while(in = getchar(), in >= \'0\' && in <= \'9\') { 61 num *= 10, num += in - \'0\'; 62 } 63 if(IsN) num = -num; 64 return true; 65 } 66 67 void initHash() { 68 for(int i = 1; i <= n; i++) { 69 b[i] = a[i]; 70 } 71 sort(b + 1, b + n + 1); 72 int p = unique(b + 1, b + n + 1) - b - 1; 73 for(int i = 1; i <= n; i++) { 74 a[i] = lower_bound(b + 1, b + n + 1, a[i]) - b; 75 } 76 } 77 78 int L[maxn]; 79 int R[maxn]; 80 int d[maxn]; 81 int tot = 0; 82 83 void dfs(int u, int fa, int dep) { 84 L[u] = ++tot; 85 d[u] = dep; 86 col[tot] = a[u]; 87 for (int i = 0; i < g[u].size(); i++) { 88 int v = g[u][i]; 89 if (v == fa)continue; 90 dfs(v, u, dep + 1); 91 } 92 R[u] = tot; 93 } 94 95 96 97 bool cmp(Q a, Q b) { 98 if(a.l / bk == b.l / bk)return a.r < b.r; 99 else return a.l / bk < b.l / bk; 100 } 101 102 103 /// find_block 104 int block[maxn], bcnt, bsize; 105 int stk[maxn], top; 106 107 void add_block(int &cnt) { 108 while(cnt--) block[stk[--top]] = bcnt; 109 bcnt++; 110 cnt = 0; 111 } 112 113 void rest_block() { 114 while(top) block[stk[--top]] = bcnt - 1; 115 } 116 117 int dfs_block(int u, int f) { 118 int s = 0; 119 for(int i = 0; i < g[u].size(); i++) { 120 int v = g[u][i]; 121 if(v == f) continue; 122 s += dfs_block(v, u); 123 if(s >= bsize) add_block(s); 124 } 125 stk[top++] = u; 126 s++; 127 if(s >= bsize) add_block(s); 128 return s; 129 } 130 131 void init_block() { 132 bsize = bk; 133 dfs_block(1, 0); 134 rest_block(); 135 } 136 137 138 /// ask_rmq 139 int fa[DEG][maxn]; 140 int dep[maxn]; 141 142 void dfs_lca(int u, int f, int depth) { 143 dep[u] = depth; 144 fa[0][u] = f; 145 for(int i = 0; i < g[u].size(); i++) { 146 int v = g[u][i]; 147 if(v != f) dfs_lca(v, u, depth + 1); 148 } 149 } 150 151 void init_lca() { 152 dfs_lca(1, -1, 0); 153 for(int k = 0; k + 1 < DEG; ++k) { 154 for(int u = 1; u <= n; ++u) { 155 if(fa[k][u] == -1) fa[k + 1][u] = -1; 156 else fa[k + 1][u] = fa[k][fa[k][u]]; 157 } 158 } 159 } 160 161 int ask_lca(int u, int v) { 162 if(dep[u] < dep[v]) swap(u, v); 163 for(int k = 0; k < DEG; ++k) { 164 if((dep[u] - dep[v]) & (1 << k)) u = fa[k][u]; 165 } 166 if(u == v) return u; 167 for(int k = DEG - 1; k >= 0; --k) { 168 if(fa[k][u] != fa[k][v]) 169 u = fa[k][u], v = fa[k][v]; 170 } 171 return fa[0][u]; 172 } 173 /// modui 174 bool vis[maxn]; 175 176 void xorNode(int u) { 177 if(vis[u]) { 178 vis[u] = false; 179 cs[cnt[a[u]]] -= b[a[u]]; 180 cnt[a[u]]--; 181 cs[cnt[a[u]]] += b[a[u]]; 182 } else { 183 vis[u] = true; 184 cs[cnt[a[u]]] -= b[a[u]]; 185 cnt[a[u]]++; 186 cs[cnt[a[u]]] += b[a[u]]; 187 } 188 } 189 190 void xorPathWithoutLca(int u, int v) { 191 if(dep[u] < dep[v]) swap(u, v); 192 while(dep[u] != dep[v]) 193 xorNode(u), u = fa[0][u]; 194 while(u != v) 195 xorNode(u), u = fa[0][u], xorNode(v), v = fa[0][v]; 196 } 197 198 void moveNode(int u, int v, int taru, int tarv) { 199 xorPathWithoutLca(u, taru); 200 xorPathWithoutLca(v, tarv); 201 //printf("debug %d %d\\n", ask_lca(u, v), ask_lca(taru, tarv)); 202 xorNode(ask_lca(u, v)); 203 xorNode(ask_lca(taru, tarv)); 204 } 205 206 207 bool cmp2(Q a, Q b) { 208 if(block[a.u] == block[b.u])return block[a.v] < block[b.v]; 209 else return block[a.u] < block[b.u]; 210 } 211 212 213 void solve() { 214 scan_d(t); 215 int c = 0; 216 while(t--) { 217 tot = 0; 218 memset(cs, 0, sizeof(cs)); 219 memset(cnt, 0, sizeof(cnt)); 220 memset(vis, 0, sizeof(vis)); 221 for(int i = 1; i <= n; i++) { 222 g[i].clear(); 223 } 224 query[1].clear(); 225 query[2].clear(); 226 scan_d(n); 227 scan_d(q); 228 for(int i = 1; i <= n; i++) { 229 scan_d(a[i]); 230 } 231 initHash(); 232 for(int i = 0; i < n - 1; i++) { 233 int u, v; 234 scan_d(u); 235 scan_d(v); 236 g[u].push_back(v); 237 g[v].push_back(u); 238 } 239 dfs(1, -1, 1); 240 init_block(); 241 init_lca(); 242 for(int i = 0; i < q; i++) { 243 int op, u, v, a, b; 244 scan_d(op); 245 scan_d(u); 246 scan_d(v); 247 scan_d(a); 248 scan_d(b); 249 query[op].push_back(Q{u, v, a, b, L[u], R[u], i}); 250 } 251 sort(query[1].begin(), query[1].end(), cmp); 252 253 254 int pl = 1, pr = 0; 255 256 for (int i = 0; i < query[1].size(); i++) { 257 int index = query[1][i].index; 258 if (pr < query[1][i].r) { 259 for (int j = pr + 1; j <= query[1][i].r; j++) { 260 cs[cnt[col[j]]] -= b[col[j]]; 261 cnt[col[j]]++; 262 cs[cnt[col[j]]] += b[col[j]]; 263 } 264 } else { 265 for (int j = pr; j > query[1][i].r; j--) { 266 cs[cnt[col[j]]] -= b[col[j]]; 267 cnt[col[j]]--; 268 cs[cnt[col[j]]] += b[col[j]]; 269 } 270 } 271 pr = query[1][i].r; 272 if (pl < query[1][i].l) { 273 for (int j = pl; j < query[1][i].l; j++) { 274 cs[cnt[col[j]]] -= b[col[j]]; 275 cnt[col[j]]--; 276 cs[cnt[col[j]]] += b[col[j]]; 277 } 278 } else { 279 for (int j = pl - 1; j >= query[1][i].l; j--) { 280 cs[cnt[col[j]]] -= b[col[j]]; 281 cnt[col[j]]++; 282 cs[cnt[col[j]]] += b[col[j]]; 283 } 284 } 285 pl = query[1][i].l; 286 ans[index] = __gcd(cs[query[1][i].a], cs[query[1][i].b]); 287 } 288 memset(cs, 0, sizeof(cs)); 289 memset(cnt, 0, sizeof(cnt)); 290 291 292 for(int i = 0; i < query[2].size(); i++) { 293 if(block[query[2][i].u] > block[query[2][i].v]) swap(query[2][i].u, query[2][i].v); 294 } 295 sort(query[2].begin(), query[2].end(), cmp2); 296 297 int nowu = 1, nowv = 1; 298 xorNode(1); 299 for(int i = 0; i < query[2].size(); i++) { 300 int index = query[2][i].index; 301 moveNode(nowu, nowv, query[2][i].u, query[2][i].v); 302 ans[index] = __gcd(cs[query[2][i].a], cs[query[2][i].b]); 303 nowu = query[2][i].u, nowv = query[2][i].v; 304 } 305 printf("Case #%d:\\n", ++c); 306 for(int i = 0; i < q; i++) { 307 printf("%lld\\n", ans[i]); 308 } 309 310 } 311 312 } 313 314 315 316 int main() { 317 318 #ifndef ONLINE_JUDGE 319 freopen("1.in", "r", stdin); 320 //freopen("1.out", "w", stdout); 321 #endif 322 //iostream::sync_with_stdio(false); 323 solve(); 324 return 0; 325 }
以上是关于(树上莫队)HDU - 5799 This world need more Zhu的主要内容,如果未能解决你的问题,请参考以下文章
算法笔记莫队算法(基础莫队,带修莫队,回滚莫队,树上莫队,二次离线莫队)