集训0403 problem A 点分治

题解:

考试时只会70分的 O ( n l o g 2 n ) 的做法,就直接点分治,对每个重心 x 维护一个 p o w e r i d i s [ i ] [ x ] 的前缀和,可以用数据结构维护。但是我们发现在下一层,我们所需要的答案只会减少一个值,所以就可以不同数据结构维护,做到 O ( n l o g n )
注意离开一颗子树后要消除它的影响。

代码:

#include<cstdio>
#include<cstring>
#include<vector>
#include<iostream>
#include<algorithm>
using namespace std;
#define LL long long
int read()
{
    int x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=(x<<3)+(x<<1)+(ch^48);ch=getchar();}
    return x*f;
}
int num[30];
void write(LL x)
{
    if(!x)putchar('0');
    else
    {
        int l=0;
        while(x)num[++l]=x%10LL,x/=10LL;
        for(int i=l;i;i--)putchar(num[i]+48);
    }
    putchar('\n');
}
const int Maxn=200010,Maxm=500010;
int n,m;
struct Edge{int y,next;}e[Maxn<<1];
int last[Maxn],len=0;
void ins(int x,int y){int t=++len;e[t].y=y;e[t].next=last[x];last[x]=t;}
vector<int>h[Maxn];
LL ans[Maxn];
int root,son[Maxn],totsize;
bool del[Maxn];
LL s[Maxn],sums=0;int S[Maxn],sumS=0;
// 权值和           个数 
int get_size(int x,int fa)
{
    int size=1;
    for(int i=last[x];i;i=e[i].next)
    {
        int y=e[i].y;
        if(y==fa||del[y])continue;
        size+=get_size(y,x);
    }
    return size;
}
int get_root(int x,int fa)
{
    int size=1,mx=0;
    for(int i=last[x];i;i=e[i].next)
    {
        int y=e[i].y;
        if(y==fa||del[y])continue;
        int t=get_root(y,x);
        mx=max(mx,t);size+=t;
    }
    son[x]=max(mx,totsize-size);
    if(root==-1)root=x;
    else if(son[x]<son[root])root=x;
    return size;
}
int mxdep;
void dfs(int x,int fa,int depth,LL o)
{
    for(int i=0;i<h[x].size();i++)
    {
        int power=h[x][i],t=power-depth;
        if(t>0)
        {
            int k=t;
            if(t>n)k=n;
            sums+=(LL)t*o;s[k]+=(LL)t*o;
            sumS+=o;S[k]+=o;
        }
    }
    for(int i=last[x];i;i=e[i].next)
    {
        int y=e[i].y;
        if(y==fa||del[y])continue;
        dfs(y,x,depth+1,o);
    }
}
LL ts;int tS;
void DFS(int x,int fa,int depth)
{
    if(depth)ts-=s[depth-1],tS-=S[depth-1];
    ans[x]+=ts-tS*(LL)(depth);
    LL tmps=ts;int tmpS=tS;
    for(int i=last[x];i;i=e[i].next)
    {
        int y=e[i].y;
        if(y==fa||del[y])continue;
        ts=tmps,tS=tmpS;
        DFS(y,x,depth+1);
    }
}
void dfs_mark(int x,int fa,int depth)
{
    for(int i=last[x];i;i=e[i].next)
    {
        int y=e[i].y;
        if(y==fa||del[y])continue;
        DFS(y,x,depth+1);
    }
}
void DFS_x(int x,int fa,int depth,int rt)
{
    for(int i=0;i<h[x].size();i++)
    {
        int power=h[x][i],t=power-depth;
        if(t>0)ans[rt]+=(LL)t;
    }
    for(int i=last[x];i;i=e[i].next)
    {
        int y=e[i].y;
        if(y==fa||del[y])continue;
        DFS_x(y,x,depth+1,rt);
    }
}
void calc(int x)
{
    DFS_x(x,0,0,x);
    dfs(x,0,0,1);
    for(int i=last[x];i;i=e[i].next)
    {
        int y=e[i].y;
        if(del[y])continue;
        dfs(y,x,1,-1);
        ts=sums,tS=sumS;
        DFS(y,x,1);
        dfs(y,x,1,1);
    }
    dfs(x,0,0,-1);
}
int Fa[Maxn];
void solve(int x)
{
    del[x]=true;
    calc(x);
    for(int i=last[x];i;i=e[i].next)
    {
        int y=e[i].y;
        if(del[y])continue;
        root=-1;
        totsize=get_size(y,x);
        get_root(y,x);Fa[root]=x;
        solve(root);
    }
}
int main()
{ 
    n=read(),m=read();
    for(int i=2;i<=n;i++)
    {
        int Fa=read();
        ins(Fa,i),ins(i,Fa);
    }
    for(int i=1;i<=m;i++)
    {
        int pos=read(),power=read();
        h[pos].push_back(power);
    }
    root=-1;
    totsize=n;
    get_root(1,0);
    solve(root);
    for(int i=1;i<=n;i++)write(ans[i]);
}

猜你喜欢

转载自blog.csdn.net/baidu_36797646/article/details/79997001