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

 

posted @ 2019-03-25 22:05  MJT12044  阅读(294)  评论(0编辑  收藏  举报