• BZOJ3924: [Zjoi2015]幻想乡战略游戏


    BZOJ3924: [Zjoi2015]幻想乡战略游戏

    https://lydsy.com/JudgeOnline/problem.php?id=3924

    分析:

    • 首先有一个很棒的思路,就是在点分树上跳重心,每次向答案最小的子分治中心移动。
    • 这个是对的,因为树上带权重心往旁边的点走答案一定更差。
    • 只需要每次能够(O(logn)​)查询即可,维护点分树上子树(dist imes d​)的和。
    • 时间复杂度(O(nlogn^2度数))

    代码:

    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #include <iostream>
    using namespace std;
    typedef long long ll;
    #define N 100050
    #define db(x) cerr<<#x<<" = "<<x<<endl
    int head[N],to[N<<1],nxt[N<<1],cnt,n,m,val[N<<1];
    int siz[N],fk[N],tot,root,dep[N],fa[N][20],used[N];
    int sz[N],f[N<<1];
    ll dis[N][20],sum[N],sum2[N];
    inline void add(int u,int v,int w=0) {
        to[++cnt]=v; nxt[cnt]=head[u]; head[u]=cnt; val[cnt]=w;
    }
    char buf[100000],*p1,*p2;
    #define nc() (p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++)
    int rd() {
        int x=0,f=1; char s=nc();
        while(s<'0') {if(s=='-') f=-1;s=nc();}
        while(s>='0') x=(((x<<2)+x)<<1)+s-'0',s=nc();
        return x*f;
    }
    void gr(int x,int y) {
        int i;
        siz[x]=1; fk[x]=0;
        for(i=head[x];i;i=nxt[i]) if(to[i]!=y&&!used[to[i]]) {
            gr(to[i],x); siz[x]+=siz[to[i]];
            fk[x]=max(fk[x],siz[to[i]]);
        }
        fk[x]=max(fk[x],tot-siz[x]);
        if(fk[x]<fk[root]) root=x;
    }
    void gd(int x,int y,int rt,int d) {
        fa[x][++dep[x]]=rt;
        dis[x][dep[x]]=d;
        int i;
        for(i=head[x];i;i=nxt[i]) if(to[i]!=y&&!used[to[i]]) {
            gd(to[i],x,rt,d+val[i]);
        }
    }
    void solve(int x) {
        used[x]=1;
        int i,all=tot;
        gd(x,0,x,0);
        for(i=head[x];i;i=nxt[i]) if(!used[to[i]]) {
            tot=siz[to[i]]; if(tot>siz[x]) tot=all-siz[x];
            root=0; gr(to[i],x); f[i]=root; solve(root);
        }
    }
    void upd(int x,int v) {
        int i;
        for(i=dep[x];i;i--) {
            sum[fa[x][i]]+=dis[x][i]*v;
            sum2[fa[x][i]]+=dis[x][i-1]*v;
            sz[fa[x][i]]+=v;
        }
    }
    ll calc(int x) {
        int i;
        ll re=0;
        for(i=dep[x];i;i--) {
            re+=sum[fa[x][i]]-sum2[fa[x][i+1]]+(sz[fa[x][i]]-sz[fa[x][i+1]])*dis[x][i];
        }
        return re;
    }
    int rt;
    ll query() {
        int x=rt,i;
        ll nowans=calc(x);
        while(1) {
            ll mn=1ll<<60; int p=0;
            for(i=head[x];i;i=nxt[i]) if(f[i]) {
                ll tmp=calc(to[i]);
                if(tmp<mn) mn=tmp,p=f[i];
            }
            if(mn<nowans) x=p,nowans=calc(x);
            else return nowans;
        }
    }
    int main() {
        n=rd(),m=rd();
        int i,x,y,z;
        for(i=1;i<n;i++) {
            x=rd(),y=rd(),z=rd(); add(x,y,z); add(y,x,z);
        }
        fk[0]=1<<30; tot=n; gr(1,0);
        rt=root; solve(root);
        while(m--) {
            x=rd(),y=rd();
            upd(x,y);
            printf("%lld
    ",query());
        }
    }
    /*
    10 5
    1 2 1
    2 3 1
    2 4 1
    1 5 1
    2 6 1
    2 7 1 
    5 8 1
    7 9 1
    1 10 1
    3 1
    2 1
    8 1
    3 1
    4 1
    */
    
  • 相关阅读:
    Arrays类
    异常
    Java日志第53天 2020.8.29
    Java日志第52天 2020.8.28
    Java日志第55天 2020.8.31
    Java日志第54天 2020.8.30
    测试:ATM
    dear mother
    Spring
    People like me
  • 原文地址:https://www.cnblogs.com/suika/p/10164778.html
Copyright © 2020-2023  润新知