bzoj4381: [POI2015]Odwiedziny

Description

给定一棵n个点的树,树上每条边的长度都为1,第i个点的权值为a[i]。
Byteasar想要走遍这整棵树,他会按照某个1到n的全排列b走n-1次,第i次他会从b[i]点走到b[i+1]点,并且这一次的步伐大小为c[i]。
对于一次行走,假设起点为x,终点为y,步伐为k,那么Byteasar会从x开始,每步往前走k步,如果最后不足k步就能到达y,那么他会一步走到y。
请帮助Byteasar统计出每一次行走时经过的所有点的权值和。

Input

第一行包含一个正整数n(2<=n<=50000)。表示节点的个数。
第二行包含n个正整数,其中第i个数为a[i](1<=a[i]<=10000),分别表示每个点的权值。
接下来n-1行,每行包含两个正整数u,v(1<=u,v<=n),表示u与v之间有一条边。
接下来一行包含n个互不相同的正整数,其中第i个数为b[i](1<=b[i]<=n),表示行走路线。
接下来一行包含n-1个正整数,其中第i个数为c[i](1<=c[i]<n),表示每次行走的步伐大小。

Output

包含n-1行,每行一个正整数,依次输出每次行走时经过的所有点的权值和

对<sqrt(n)的步长,预处理从每个点向上以每个步长走到根的权值和

对于更大的步长可以暴力计算

#include<bits/stdc++.h>
const int N=50007;
char buf[N*50],*ptr=buf-1;
int _(){
    int x=0,c=*++ptr;
    while(c<48)c=*++ptr;
    while(c>47)x=x*10+c-48,c=*++ptr;
    return x;
}
int n,a[N],b[N],md=1,B,sum[N][233];
int es[N*2],enx[N*2],e0[N],ep=2;
int fa[N],sz[N],dep[N],son[N],top[N],id[N],idr[N],idp=0;
void maxs(int&a,int b){if(a<b)a=b;}
void f1(int w,int pa){
    dep[w]=dep[fa[w]=pa]+1;
    maxs(md,dep[w]);
    sz[w]=1;
    for(int i=e0[w];i;i=enx[i]){
        int u=es[i];
        if(u!=pa){
            f1(u,w);
            sz[w]+=sz[u];
            if(sz[u]>sz[son[w]])son[w]=u;
        }
    }
}
void f2(int w,int tp){
    top[w]=tp;
    idr[id[w]=++idp]=w;
    if(son[w])f2(son[w],tp);
    for(int i=e0[w];i;i=enx[i]){
        int u=es[i];
        if(u!=fa[w]&&u!=son[w])f2(u,u);
    }
}
int lca(int x,int y){
    int a=top[x],b=top[y];
    while(a!=b){
        if(dep[a]<dep[b])y=fa[b],b=top[y];
        else x=fa[a],a=top[x];
    }
    return dep[x]<dep[y]?x:y;
}
int up(int x,int d){
    if(d>=dep[x])return 0;
    int y=dep[x]-d,a=top[x];
    while(dep[a]>y)x=fa[a],a=top[x];
    return idr[id[x]-dep[x]+y];
}
int cal(int x,int y,int v){
    if(dep[x]<=dep[y])return 0;
    int s=0;
    if(v<=B){
        s+=sum[x][v];
        int r=v-(dep[x]-dep[y])%v;
        s-=sum[r==v?y:up(y,r)][v];
    }else{
        while(dep[x]>dep[y])s+=a[x],x=up(x,v);
    }
    return s;
}
void calc(int x,int y,int v){
    int z=lca(x,y),r=(dep[x]+dep[y]-dep[z]*2)%v,ans=0;
    ans+=cal(x,z,v);
    if(r){
        ans+=a[y];
        y=up(y,r);
    }
    ans+=cal(y,fa[z],v);
    printf("%d
",ans);
}
void f3(int w){
    for(int i=1;i<=B;++i)sum[w][i]=sum[up(w,i)][i]+a[w];
    for(int i=e0[w];i;i=enx[i]){
        int u=es[i];
        if(u!=fa[w])f3(u);
    }
}
int main(){
    buf[fread(buf,1,sizeof(buf),stdin)]=0;
    n=_();
    for(int i=1;i<=n;++i)a[i]=_();
    for(int i=1,a,b;i<n;++i){
        a=_();b=_();
        es[ep]=b;enx[ep]=e0[a];e0[a]=ep++;
        es[ep]=a;enx[ep]=e0[b];e0[b]=ep++;
    }
    f1(1,0);f2(1,1);
    B=sqrt(md+1)*0.7+1;
    f3(1);
    for(int i=1;i<=n;++i)b[i]=_();
    for(int i=1;i<n;++i)calc(b[i],b[i+1],_());
    return 0;
}
原文地址:https://www.cnblogs.com/ccz181078/p/6417756.html