LOJ #2135. 「ZJOI2015」幻想乡战略游戏
#2135. 「ZJOI2015」幻想乡战略游戏
分析:
动态点分治,求加权重心,带修改。
考虑如果知道了一个点s,如何求答案,那么首先可以点分治的思想,求每个联通块内所有点到分治中心距离和,然后加上分治中心到s的距离。
当然有一部分会算重,就是s在i中,以fa[i]为分治中心的时候,就会算重s到i的连通块的部分,于是在记录每个联通块到此分治中心在点分树上的父节点的距离和。
那么随机从一个分治中心出发,每次遍历它周围的点,如果周围的点存在更优的情况,那么往这个方向走更优,所有就往这方向走,即到这个点所在连通块的分治中心位置。
代码:
#include<cstdio> #include<algorithm> #include<iostream> #include<cstring> #include<cmath> #include<cctype> #include<set> #include<queue> #include<vector> #include<map> #include<bitset> #define fore(i, u, v) for (int i = head[u], v = e[i].to; i; i = e[i].nxt, v = e[i].to) using namespace std; typedef long long LL; inline int read() { int x=0,f=1;char ch=getchar();for(;!isdigit(ch);ch=getchar())if(ch=='-')f=-1; for(;isdigit(ch);ch=getchar())x=x*10+ch-'0';return x*f; } const int N = 200005; struct Edge { int to, nxt, w; } e[N << 1]; int head[N], Log[N], pos[N], siz[N], fa[N], val[N]; bool vis[N]; int En, Index, Mn, Root, Now; LL dep[N], f[N][20], va[N], vb[N], sum[N]; inline void add_edge(int u,int v,int w) { ++En; e[En].to = v, e[En].w = w, e[En].nxt = head[u]; head[u] = En; ++En; e[En].to = u, e[En].w = w, e[En].nxt = head[v]; head[v] = En; } void predfs(int u,int fa) { pos[u] = ++Index; f[Index][0] = dep[u]; fore(i, u, v) if (v != fa) dep[v] = dep[u] + e[i].w, predfs(v, u), f[++Index][0] = dep[u]; } void preinit() { for (int i = 2; i <= Index; ++i) Log[i] = Log[i >> 1] + 1; for (int j = 1; j <= Log[Index]; ++j) for (int i = 1; i + (1 << j) - 1 <= Index; ++i) f[i][j] = min(f[i][j - 1], f[i + (1 << (j - 1))][j - 1]); } void getroot(int u,int fa,int Size) { int mx = 0; siz[u] = 1; fore(i, u, v) if (!vis[v] && v != fa) getroot(v, u, Size), siz[u] += siz[v], siz[v] > mx ? mx = siz[v] : mx; mx = max(mx, Size - siz[u]); if (mx < Mn) Mn = mx, Root = u; } void solve(int u) { vis[u] = 1; fore(i, u, v) if (!vis[v]) Mn = 1e9, getroot(v, u, siz[v]), fa[Root] = u, val[i] = Root, solve(Root); } LL LCA(int x,int y) { x = pos[x], y = pos[y]; if (x > y) swap(x, y); int k = Log[y - x + 1]; return min(f[x][k], f[y - (1 << k) + 1][k]); } LL getdis(int x,int y) { return dep[x] + dep[y] - 2 * LCA(x, y); } LL Calc(int x) { LL ans = 0; for (int i = x; i; i = fa[i]) ans += va[i] + sum[i] * getdis(x, i); for (int i = x; fa[i]; i = fa[i]) ans -= vb[i] + sum[i] * getdis(x, fa[i]); return ans; } void update() { int x = read(), y = read(); for (int i = x; i; i = fa[i]) va[i] += y * getdis(x, i), sum[i] += y; for (int i = x; fa[i]; i = fa[i]) vb[i] += y * getdis(x, fa[i]); } void query() { int x = Now, y; LL Mn, tmp; while (1) { Mn = Calc(x); y = x; fore(i, x, v) if (val[i] && (tmp = Calc(v)) < Mn) Mn = tmp, y = val[i]; if (y == x) break; x = y; } cout << Mn << "\n"; } int main() { int n = read(), Q = read(); for (int u, v, w, i = 1; i < n; ++i) u = read(), v = read(), w = read(), add_edge(u, v, w); predfs(1, 0); preinit(); Mn = 1e9, getroot(1, 0, n); Now = Root; solve(Root); while (Q --) update(), query(); return 0; }