zoukankan      html  css  js  c++  java
  • 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 << "
    ";
    }
    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;
    }
  • 相关阅读:
    开发一个App的成本是多少?
    自定义Drawable
    数据库服务软件类型和配置redis
    分库分表
    创建视图
    部署MYSQL高可用集群
    读写分离《二》
    读写分离和多实例
    部署mysql主从同步
    备份和恢复
  • 原文地址:https://www.cnblogs.com/mjtcn/p/10597052.html
Copyright © 2011-2022 走看看