GDOI2016模拟8.16逃离牛棚

来源:互联网 发布:中级java工程师薪资 编辑:程序博客网 时间:2024/05/21 22:23

题目
现在正是Farmer John的农场里面挤奶的季节了!可是奶牛们全都跑了。FJ需要把他们都圈起来,需要你帮他搜寻奶牛。
FJ的农场里有一排N(1<=N<=200,000)个(编号为1..N)的草场,这N个农场由N-1条双向路连接。牛棚在草场1,而且牛棚能通向任意草场。
FJ的奶牛今天早上都在他们的草场上,但谁知道他们现在跑到哪里去了。FJ知道奶牛们只会从牛棚逃出去,而且他们太懒了所以不能跑超过L的距离。对于每个草场,FJ想知道奶牛们能从这个草场出发能到达的多少个不同的草场,使得奶牛们离牛棚更远。
注意:需要用64位整型存储表示距离的值(int64 in Pascal,long long in C/C++,long in Java)。

这题正难则反(这题是弱化版的,直接上就行,强化版的允许往祖先走,再往下其他分支走)

我们可以将每个点对其他点答案的贡献求出来,即往上距离L以内所有点答案+1,这个可以链剖+线段树(或用数组打标记前缀和,这个少个log)

贴代码

#include<iostream>#include<algorithm>#include<cstdio>#define N 200001using namespace std;int n;long long L;int b[N][2],h[N],f[4*N],g[N],bz[N],fa[N][18],ans[N],bz1[N];long long len[N][18];struct node{    long long dis;    int v,next;}a[N];void ins(int x,int y,long long z){    static int sum=0;    a[++sum].v=y,a[sum].dis=z,a[sum].next=g[x],g[x]=sum;} void init(){    static int x;    long long y;    scanf("%d %lld",&n,&L);    for (int i=2;i<=n;i++){        scanf("%d %lld",&x,&y);        fa[i][0]=x,len[i][0]=y;        ins(x,i,y);    }}void dfs(int x){    for (int i=0;fa[fa[x][i]][i];fa[x][i+1]=fa[fa[x][i]][i],len[x][i+1]=len[x][i]+len[fa[x][i]][i],i++);    for (int i=g[x];i;i=a[i].next){        dfs(a[i].v);        if (b[x][0]<b[a[i].v][0]+1)            b[x][0]=b[a[i].v][0]+1,b[x][1]=a[i].v;    }}void dfs1(int x){    static int sum=0;    bz1[bz[x]=++sum]=x;    if (b[x][1])        h[b[x][1]]=h[x],dfs1(b[x][1]);    for (int i=g[x];i;i=a[i].next)        if (a[i].v!=b[x][1])            h[a[i].v]=a[i].v,dfs1(a[i].v);}void pre(){    dfs(1);    h[1]=1;    dfs1(1);}void change(int l,int r,int s,int ll,int rr){    if (rr<l||r<ll)return;    if (ll<=l&&r<=rr){        ++f[s];        return;    }    change(l,(l+r)/2,s+s,ll,rr);    change((l+r)/2+1,r,s+s+1,ll,rr);}void up(int x,int y){    while (true)        if (bz[h[x]]<=bz[y]){            change(1,n,1,bz[y],bz[x]);            return;        }else            change(1,n,1,bz[h[x]],bz[x]),x=fa[h[x]][0];}int get(int x){    static int i;    static long long y;    y=0,i=17;    while (y+len[x][0]<=L&&x!=1){        for (;y+len[x][i]>L||!fa[x][i];i--);        y+=len[x][i],x=fa[x][i];    }    return x;}void build(int l,int r,int s){    if (l==r){        ans[bz1[l]]=f[s];        return;    }    f[s+s]+=f[s],f[s+s+1]+=f[s];    build(l,(l+r)/2,s+s),build((l+r)/2+1,r,s+s+1);}void work(){    for (int i=1;i<=n;i++)        up(i,get(i));    build(1,n,1);}void write(){    for (int i=1;i<=n;i++)        printf("%d\n",ans[i]);}int main(){    init();    pre();    work();    write();    return 0;}
0 0
原创粉丝点击