[BZOJ3924][Zjoi2015]幻想乡战略游戏(动态点分治)
2018-03-24 22:44
441 查看
看到数据范围和6s的时限,得(cai)出是一道动态点分治。
这道题有一个巧妙的思路:
假设当前补给站为uu,并强制以uu为根,vv为uu的一个子节点,sumdusumdu和sumdvsumdv分别为uu的子树内的dd之和以及vv的子树内的dd之和,len(u,v)len(u,v)为边(u,v)(u,v)的长度。
如果将补给站迁移到点vv,那么vv的子树内的点到补给站的距离减少了len(u,v)len(u,v),其他的点到补给站的距离增加了len(u,v)len(u,v)。也就是说,补给站迁移到点vv时,代价的增量为:
len(u,v)×(sumdu−sumdv−sumdv)len(u,v)×(sumdu−sumdv−sumdv)
整理一下,得出性质:uu为根,vv为uu的子节点,补给站在vv比uu优,当且仅当:
2×sumdv>sumdu2×sumdv>sumdu
显然满足条件的vv最多只有一个。
这时候,如果没有满足条件的vv,则uu为最优位置。否则最优位置在vv的子树内。
考虑动态点分治时每个点维护dd,sumdsumd,sumpdsumpd三个值,分别表示:
dudu:点uu的dd值。
sumdusumdu:点uu的子树内所有的dd值之和。
sumpdusumpdu:如果uu为根,则该值等于树中所有点vv的dis(v,u)×dvdis(v,u)×dv之和,否则等于uu的子树内所有点vv的dis(v,fau)×dvdis(v,fau)×dv之和。
(dis(a,b)dis(a,b)为aa和bb两点在原树中的距离,faufau为点uu在分治树上的父节点)
修改比较简单,从uu开始不断地往faufau更新三个值即可。
询问时,先把最优解暂定为分治树的根节点。
假设现在到了点uu的分治子树,并且发现最优解在vv的分治子树内(vv为uu在分治树上的一个子节点,原树上有边(u,w)(u,w)并且ww在vv的分治子树内)
则可以转移到vv的分治子树内求解。
首先计算出uu的分治子树内(除vv的分治子树内的点之外)的所有点到ww的dis×ddis×d之和(可以使用sumpdsumpd计算得出),这样vv的分治子树之外节点的影响就计算好了。
此外,还要考虑节点ww的影响因素:实际上对于uu的分治子树内但在vv的分治子树之外的一个点kk,上面的计算只是计算好了w−>kw−>k这一段路径的影响,而v−>wv−>w这一段路径的影响还没就算出来。所以,还需要把dwdw加上sumdu−sumdvsumdu−sumdv(对应的sumdsumd和sumpdsumpd也要跟着调整),这样就处理好了v−>wv−>w这一段路径的影响。这样就能进入vv的分治子树进行求解了。但vv的分治子树求解完毕后,还需要把dwdw恢复原值。
最好要使用RMQ求LCA来查询两点距离。
复杂度O(nlog2n)O(nlog2n)(设n,qn,q同阶)
第一次写动态点分治,调了一整个下午
代码:
这道题有一个巧妙的思路:
假设当前补给站为uu,并强制以uu为根,vv为uu的一个子节点,sumdusumdu和sumdvsumdv分别为uu的子树内的dd之和以及vv的子树内的dd之和,len(u,v)len(u,v)为边(u,v)(u,v)的长度。
如果将补给站迁移到点vv,那么vv的子树内的点到补给站的距离减少了len(u,v)len(u,v),其他的点到补给站的距离增加了len(u,v)len(u,v)。也就是说,补给站迁移到点vv时,代价的增量为:
len(u,v)×(sumdu−sumdv−sumdv)len(u,v)×(sumdu−sumdv−sumdv)
整理一下,得出性质:uu为根,vv为uu的子节点,补给站在vv比uu优,当且仅当:
2×sumdv>sumdu2×sumdv>sumdu
显然满足条件的vv最多只有一个。
这时候,如果没有满足条件的vv,则uu为最优位置。否则最优位置在vv的子树内。
考虑动态点分治时每个点维护dd,sumdsumd,sumpdsumpd三个值,分别表示:
dudu:点uu的dd值。
sumdusumdu:点uu的子树内所有的dd值之和。
sumpdusumpdu:如果uu为根,则该值等于树中所有点vv的dis(v,u)×dvdis(v,u)×dv之和,否则等于uu的子树内所有点vv的dis(v,fau)×dvdis(v,fau)×dv之和。
(dis(a,b)dis(a,b)为aa和bb两点在原树中的距离,faufau为点uu在分治树上的父节点)
修改比较简单,从uu开始不断地往faufau更新三个值即可。
询问时,先把最优解暂定为分治树的根节点。
假设现在到了点uu的分治子树,并且发现最优解在vv的分治子树内(vv为uu在分治树上的一个子节点,原树上有边(u,w)(u,w)并且ww在vv的分治子树内)
则可以转移到vv的分治子树内求解。
首先计算出uu的分治子树内(除vv的分治子树内的点之外)的所有点到ww的dis×ddis×d之和(可以使用sumpdsumpd计算得出),这样vv的分治子树之外节点的影响就计算好了。
此外,还要考虑节点ww的影响因素:实际上对于uu的分治子树内但在vv的分治子树之外的一个点kk,上面的计算只是计算好了w−>kw−>k这一段路径的影响,而v−>wv−>w这一段路径的影响还没就算出来。所以,还需要把dwdw加上sumdu−sumdvsumdu−sumdv(对应的sumdsumd和sumpdsumpd也要跟着调整),这样就处理好了v−>wv−>w这一段路径的影响。这样就能进入vv的分治子树进行求解了。但vv的分治子树求解完毕后,还需要把dwdw恢复原值。
最好要使用RMQ求LCA来查询两点距离。
复杂度O(nlog2n)O(nlog2n)(设n,qn,q同阶)
第一次写动态点分治,调了一整个下午
代码:
#include <cmath> #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #define For(i, a, b) for (i = a; i <= b; i++) #define Edge(u) for (int e = adj[u], v; e; e = nxt[e]) #define Edge2(u) for (int e = adj2[u], v; e; e = nxt2[e]) using namespace std; inline int read() { int res = 0; bool bo = 0; char c; while (((c = getchar()) < '0' || c > '9') && c != '-'); if (c == '-') bo = 1; else res = c - 48; while ((c = getchar()) >= '0' && c <= '9') res = (res << 3) + (res << 1) + (c - 48); return bo ? ~res + 1 : res; } typedef long long ll; const int N = 1e5 + 5, M = N << 1, LogN = 22; int n, q, ecnt, nxt[M], adj , go[M], val[M], sze , maxs , G, dep , dis , m, a[M], Log[M], RMQ[M][LogN], fir , fa , Root, ecnt2, nxt2 , adj2 , go2 , sc2 ; ll d , sumd , sumpd ; bool vis ; void add_edge(int u, int v, int w) { nxt[++ecnt] = adj[u]; adj[u] = ecnt; go[ecnt] = v; val[ecnt] = w; nxt[++ecnt] = adj[v]; adj[v] = ecnt; go[ecnt] = u; val[ecnt] = w; } void add_edge2(int u, int v, int w) { nxt2[++ecnt2] = adj2[u]; adj2[u] = ecnt2; go2[ecnt2] = v; sc2[ecnt2] = w; } void dfs(int u, int fu) { dep[u] = dep[fu] + 1; a[fir[u] = ++m] = u; Edge(u) { if ((v = go[e]) == fu) continue; dis[v] = dis[u] + val[e]; dfs(v, u); a[++m] = u; } } void initRMQ() { int i, j; For (i, 1, m) RMQ[i][0] = a[i]; For (j, 1, 18) For (i, 1, m - (1 << j) + 1) { int x = RMQ[i][j - 1], y = RMQ[i + (1 << j - 1)][j - 1]; RMQ[i][j] = dep[x] < dep[y] ? x : y; } } int dist(int u, int v) { int l = fir[u], r = fir[v]; if (l > r) swap(l, r); int x = Log[r - l + 1], r1 = RMQ[l][x], r2 = RMQ[r - (1 << x) + 1][x]; int lca = dep[r1] < dep[r2] ? r1 : r2; return dis[u] + dis[v] - (dis[lca] << 1); } void dfs1(int u, int fu) { sze[u] = 1; for (int e = adj[u], v; e; e = nxt[e]) { if ((v = go[e]) == fu || vis[v]) continue; dfs1(v, u); sze[u] += sze[v]; } } void dfs2(int r, int u, int fu) { maxs[u] = sze[r] - sze[u]; Edge(u) { if ((v = go[e]) == fu || vis[v]) continue; maxs[u] = max(maxs[u], sze[v]); } if (maxs[u] < maxs[G]) G = u; Edge(u) if ((v = go[e]) != fu && !vis[v]) dfs2(r, v, u); } void calcG(int u) {dfs1(u, 0); G = u; dfs2(u, u, 0);} int dfs3(int u, int fu) { calcG(u); if (!Root) Root = G; vis[G] = 1; fa[G] = fu; int t = G; Edge(G) { if (vis[v = go[e]]) continue; int w = dfs3(v, t); add_edge2(t, w, v); } return t; } void change(int u, int delta) { int v = u; d[u] += delta; while (u) { sumd[u] += delta; sumpd[u] += 1ll * delta * dist(v, fa[u] ? fa[u] : u); u = fa[u]; } } ll exc(int u, int w, int x) { ll ans = 0, cnt = d[u]; Edge2(u) if ((v = go2[e]) != w) ans += sumpd[v], cnt += sumd[v]; d[x] += cnt; return ans + cnt * dist(u, x); } ll query(ll ans, int u) { Edge2(u) if ((sumd[v = go2[e]] << 1) > sumd[u]) { ll wr = d[sc2[e]], tmp, delta = exc(u, v, sc2[e]); tmp = d[sc2[e]] - wr; for (int w = sc2[e]; w != u; w = fa[w]) sumd[w] += tmp, sumpd[w] += tmp * dist(sc2[e], fa[w] ? fa[w] : w); ll nans = 0; for (int z = adj2[v]; z; z = nxt2[z]) nans += sumpd[go2[z]]; ans = delta + query(nans, v); for (int w = sc2[e]; w != u; w = fa[w]) sumd[w] -= tmp, sumpd[w] -= tmp * dist(sc2[e], fa[w] ? fa[w] : w); d[sc2[e]] = wr; return ans; } return ans; } int main() { int i, x, y, z; n = read(); q = read(); Log[0] = -1; For (i, 1, n << 1) Log[i] = Log[i >> 1] + 1; For (i, 1, n - 1) x = read(), y = read(), z = read(), add_edge(x, y, z); dfs(1, 0); initRMQ(); dfs3(1, 0); while (q--) { x = read(); y = read(); change(x, y); printf("%lld\n", query(sumpd[Root], Root)); } return 0; }
相关文章推荐
- [ZJOI2015][bzoj3924] 幻想乡战略游戏 [动态点分治]
- BZOJ 3924: [Zjoi2015]幻想乡战略游戏(动态点分治)
- [BZOJ3924][ZJOI2015]幻想乡战略游戏(动态点分治)
- BZOJ 3924: [Zjoi2015]幻想乡战略游戏(动态点分治)
- 【bzoj3924】[Zjoi2015]幻想乡战略游戏 动态点分治
- bzoj3924 [Zjoi2015]幻想乡战略游戏(动态点分治)
- 【BZOJ3924】【Zjoi2015】幻想乡战略游戏(树链剖分+点分治)
- [BZOJ]3924 [ZJOI2015] 幻想乡战略游戏 树链剖分
- bzoj 3924: [Zjoi2015]幻想乡战略游戏 动态树分治
- bzoj 3924: [Zjoi2015]幻想乡战略游戏
- 【BZOJ3924】幻想乡战略游戏(动态点分治)
- BZOJ 3924 Zjoi2015 幻想乡战略游戏 动态树分治
- BZOJ 3924: [Zjoi2015]幻想乡战略游戏
- [BZOJ3924][ZJOI2015]幻想乡战略游戏-动态树分治
- 【BZOJ3924】幻想乡战略游戏(动态点分治)
- 【BZOJ3924】[Zjoi2015]幻想乡战略游戏 动态树分治
- BZOJ 3924: [Zjoi2015]幻想乡战略游戏
- [BZOJ3924][Zjoi2015][点分树][暴力]幻想乡战略游戏
- 【BZOJ 3924】【ZJOI 2015】幻想乡战略游戏
- 【BZOJ 3924】[Zjoi2015]幻想乡战略游戏