首页 > 学院 > 开发设计 > 正文

bzoj3052糖果公园 树上莫队

2019-11-08 18:27:39
字体:
来源:转载
供稿:网友

题目传送门: http://www.lydsy.com/JudgeOnline/PRoblem.php?id=3052

最近不太想写博客了,退役前还是写点学的东西吧。 这个坑从我会莫队开始就挖在这里了。。 莫队: http://blog.csdn.net/nickwzk/article/details/52954097 可是在树上怎么莫队呢? 这有两种非常妙的方法,dfs序和王室联邦分块(bzoj1086) 我看网上大家都用dfs序的版本,就作死写了一个王室联邦分块的,然后常数巨大(大概不怪王室联邦分块怪我常数大 然后这个是一个树上的带修改的莫队,所以当块大小等于n23的时候复杂度最优。 借用王室联邦分块,另块大小为B=n23,块的个数为p。每个节点i属于belong[i]。我们可以发现(belong[u], belong[v])最多p2个取值。 因为已经按块排好序了,所以我们可以将情况分为两种。一种是当前移动后u,v都在原块内,那么移动总复杂度为O(B∗q;另一种是u,v不在原来的块内,那么这种情况最多出现p2次,每次移动最坏情况为O(n+n+q)。又因为n与q同阶,所以可以得到总的时间复杂度为O(n53 然后在树上移动的时候,记录一个vis数组,到达一个点的时候将其取反,如果已经存在当前统计中就将它删去,若没有就将它加入。对于时间的修改可以放在移动之前也可以放在移动之后,必须要使这个操作可逆,所以修改之后要记录下修改之前的糖果种类。 对于lca(u,v),要在记录答案之前加上,在记录答案之后删去。 自带巨大常数的Code:

#include <cstdio>#include <algorithm>#include <cmath>#include <cstring>using namespace std;const int MAXN = 100003;const int S = 17;struct Edge { int to, nxt; Edge() {} Edge(int _to, int _nxt):to(_to), nxt(_nxt) {}}e[MAXN << 1];int h[MAXN], p;int stack[MAXN], top, belong[MAXN], cnt, sz;struct Node { int l, r, id, ti; bool Operator < (const Node &x) const { return belong[l] < belong[x.l] || (belong[l] == belong[x.l] && belong[r] < belong[x.r]) || (belong[l] == belong[x.l] && belong[r] == belong[x.r] && ti < x.ti); }}q[MAXN];struct Node2 { int l, r, ti;}QQ[MAXN];int n, m, Q, Q0, Q1;int V[MAXN], W[MAXN], C[MAXN];int fa[MAXN][S + 3], dep[MAXN];long long ans[MAXN], tans;int vis[MAXN], cur[MAXN];long long sum[MAXN];int l, r, tm;inline int read() { int x = 0; char ch = getchar(); bool fg = 0; while(ch < '0' || ch > '9') { if(ch == '-') fg = 1; ch = getchar(); } while(ch >= '0' && ch <= '9') { x = x * 10 + ch - '0'; ch = getchar(); } return fg ? -x : x;}inline void add_edge(int u, int v) { e[++p] = Edge(v, h[u]); h[u] = p; e[++p] = Edge(u, h[v]); h[v] = p;}void dfs(int u, int f) { fa[u][0] = f; dep[u] = dep[f] + 1; int bot = top; for(int i = h[u]; i; i = e[i].nxt) { int v = e[i].to; if(v == f) continue; dfs(v, u); if(top - bot >= sz) { cnt++; while(top != bot) belong[stack[top--]] = cnt; } } stack[++top] = u;}void G(int &u, int step) { for(int i = 0; i < S; i++) if((1 << i) & step) u = fa[u][i];}int lca(int u, int v) { if(dep[u] > dep[v]) swap(u, v); G(v, dep[v] - dep[u]); if(u == v) return u; for(int i = S; i >= 0; i--) if(fa[u][i] != fa[v][i]) { u = fa[u][i]; v = fa[v][i]; } return fa[u][0];}inline void modify(int u) { tans -= V[C[u]] * sum[cur[C[u]]]; cur[C[u]] += vis[u]; vis[u] = -vis[u]; tans += V[C[u]] * sum[cur[C[u]]];}inline void update(int u, int v) { if(u == v) return; if(dep[u] > dep[v]) swap(u, v); while(dep[v] > dep[u]) { modify(v); v = fa[v][0]; } while(u != v) { modify(u); modify(v); u = fa[u][0]; v = fa[v][0]; }}inline void upd(int t) { if(vis[qq[t].l] == -1) { modify(qq[t].l); swap(C[qq[t].l], qq[t].r); modify(qq[t].l); } else swap(C[qq[t].l], qq[t].r);}inline void moveto(int u, int v) { update(l, u); update(r, v); l = u; r = v;}int main() { n = read(); m = read(); Q = read(); sz = (int)pow(n, 2.0 / 3.0); for(int i = 1; i <= m; i++) V[i] = read(); for(int i = 1; i <= n; i++) W[i] = read(); for(int i = 1, u, v; i < n; i++) { u = read(); v = read(); add_edge(u, v); } for(int i = 1; i <= n; i++) { C[i] = read(); vis[i] = 1; sum[i] = sum[i - 1] + W[i]; } for(int i = 1, tp; i <= Q; i++) { tp = read(); if(tp) { ++Q1; q[Q1].l = read(); q[Q1].r = read(); q[Q1].id = Q1; q[Q1].ti = i; } else { ++Q0; qq[Q0].l = read(); qq[Q0].r = read(); qq[Q0].ti = i; } } dfs(1, 0); while(top) belong[stack[top--]] = cnt; sort(q + 1, q + Q1 + 1); for(int k = 1; k <= S; k++) { for(int i = 1; i <= n; i++) { fa[i][k] = fa[fa[i][k - 1]][k - 1]; } } for(int i = 1; i <= Q1; i++) { if(belong[q[i].l] > belong[q[i].r]) swap(q[i].l, q[i].r); moveto(q[i].l, q[i].r); int lc = lca(l, r); modify(lc); while(qq[tm + 1].ti < q[i].ti && tm < Q0) upd(++tm); while(qq[tm].ti > q[i].ti) upd(tm--); ans[q[i].id] = tans; modify(lc); } for(int i = 1; i <= Q1; i++) printf("%lld/n", ans[i]); return 0;}
发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表