(树上莫队)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的主要内容,如果未能解决你的问题,请参考以下文章

树上莫队算法

树上骗分: 莫队Ⅲ

算法笔记莫队算法(基础莫队,带修莫队,回滚莫队,树上莫队,二次离线莫队)

Nowcoder挑战赛39F(模板树上莫队)

[WC2013][luogu4074] 糖果公园 [树上带修改莫队]

树上莫队