• 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;
    }
  • 相关阅读:
    C语言 · 字符串输入输出函数
    C语言 · 判定字符位置
    剑指offer二之替换空格
    剑指offer一之二维数组中的查找
    算法复杂度:时间复杂度与空间复杂度
    二分查找法
    信息熵
    K-means算法的原理、优缺点及改进(转)
    office2013安装与卸载
    Deep Learning (中文版&英文版)
  • 原文地址:https://www.cnblogs.com/ccz181078/p/6417756.html
Copyright © 2020-2023  润新知