1. 程式人生 > >LOJ #2135. 「ZJOI2015」幻想鄉戰略遊戲

LOJ #2135. 「ZJOI2015」幻想鄉戰略遊戲

dep turn name 如何 zjoi return ace queue oid

#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; }

LOJ #2135. 「ZJOI2015」幻想鄉戰略遊戲