• 2018.12.29-dtoj-3626


    题目描述:

    有一棵N个节点的树, 令d(i,j)为i到j经过的边的条数。有M个炸弹, 第i个炸弹在节点posi上, 威力为power i,它会对所有节点j造成max(0,power i−d(posi,j))的伤害。
    求出每个节点最终受到的伤害。

    算法标签:点分治

    思路:

    考虑对于每次求点,仅求以当前重心为根时,不同子树之间的贡献。每次处理出炸弹到根的距离和每个点到根距离,我们会发现对于在同一个子树的答案我们会多算,所以再对每个子树单独做一次,减去多算的答案。

    以下代码:

    #include<bits/stdc++.h>
    #define il inline
    #define LL long long
    #define _(d) while(d(isdigit(ch=getchar())))
    using namespace std;
    const int N=2e5+5,M=5e5+5;
    int sz[N],d[N],son[N],rt,size,md,A[N],tt,num[N];bool vis[N];
    int n,m,head[N],ne[N<<1],to[N<<1],cnt,hd[N],val[M],nx[M],tot;LL res[N],sum[N];
    il int read(){int x;char ch;_(!);x=ch^48;_()x=(x<<1)+(x<<3)+(ch^48);return x;}
    il void insert(int x,int y){ne[++cnt]=head[x];head[x]=cnt;to[cnt]=y;}
    il void ins(int x,int y){nx[++tot]=hd[x];hd[x]=tot;val[tot]=y;}
    il void getrt(int x,int fa){
        son[x]=sz[x]=1;
        for(int i=head[x];i;i=ne[i]){
            if(fa==to[i]||vis[x])continue;
            getrt(to[i],x);sz[x]+=sz[to[i]];
            son[x]=max(son[x],sz[to[i]]);
        }
        son[x]=max(son[x],size-sz[x]);
        if(son[x]<son[rt])rt=x;
    }
    il void getmd(int x,int fa){
        if(d[x]>md)md=d[x];A[++tt]=x;
        for(int i=head[x];i;i=ne[i]){
            if(fa==to[i]||vis[to[i]])continue;
            d[to[i]]=d[x]+1;getmd(to[i],x);
        }
    }
    il void dfs(int x,int fa){
        for(int i=hd[x];i;i=nx[i]){
            int v=min(val[i]-d[x],md);
            if(v>0)sum[v]+=val[i]-d[x],num[v]++;
        }
        for(int i=head[x];i;i=ne[i]){
            if(fa==to[i]||vis[to[i]])continue;
            dfs(to[i],x);
        }
    }
    il void work(int x,int dep,int f){
        tt=md=0;d[x]=dep;getmd(x,0);md++;
        for(int i=0;i<=md;i++)sum[i]=0,num[i]=0;
        dfs(x,0);
        for(int i=1;i<=md;i++)sum[i]+=sum[i-1],num[i]+=num[i-1];
        for(int i=1;i<=tt;i++){
            int u=A[i];
            res[u]+=1ll*(sum[md]-sum[d[u]]-1ll*d[u]*(num[md]-num[d[u]]))*f;
        }
    }
    il void solve(int x){
        vis[x]=1;work(x,0,1);
        for(int i=head[x];i;i=ne[i]){
            if(vis[to[i]])continue;
            work(to[i],1,-1);
        }
        for(int i=head[x];i;i=ne[i]){
            if(vis[to[i]])continue;
            rt=0;getrt(to[i],x);solve(rt);
        }
    }
    int main()
    {
        n=read();m=read();
        for(int i=2;i<=n;i++){int x=read();insert(i,x);insert(x,i);}
        for(int i=1;i<=m;i++){int x=read(),y=read();ins(x,y);}
        size=n;son[0]=n;getrt(1,0);solve(rt);
        for(int i=1;i<=n;i++)printf("%lld
    ",res[i]);
        return 0;
    }
    View Code
  • 相关阅读:
    WCF上传下载文件
    WCF使用相关
    .net WCF WF4.5 状态机、书签与持久化
    .net WCF WF4.5
    CSS小东西
    asp.net mvc导出execl_转载
    winform自定义控件开发
    html问题汇总
    工作中的小东西
    jQuery事件
  • 原文地址:https://www.cnblogs.com/Jessie-/p/10199129.html
Copyright © 2020-2023  润新知