天天爱跑步

来源:互联网 发布:登陆淘宝网店 编辑:程序博客网 时间:2024/04/28 23:08

天天爱跑步

(File IO): input:running.in output:running.out

Time Limits: 2s Memory Limits: 512MB

Description
Description
Input
Input
Output
Output
Sample Input
Sample Input1:

6 32 31 21 44 54 60 2 5 1 2 31 51 32 6

Sample Input2:

5 31 22 32 41 50 1 0 3 03 11 45 5

Sample Output
Sample Output1:

2 0 0 1 1 1

Sample Output2:

1 2 1 0 1

Hint
Hint
Data Constraint
Data
Tips


解题思路


以1为根遍历一遍,求出每一个点的的层数fl[i]

对于每一对s,t都会有他们的lca,则s到t的长度len为fl[s]+fl[t]-2fl[lca]我们可以分为s->lca,lca->t考虑:
Solution

对于路径s->lca的点d如图①,在第w[d]个时间点上到达需满足

wd+fld=fls

对于路径lca->t的点d如图②,在第w[d]个时间点上到达需满足
fldfllca+flsfllca=wd
||
lenflt=wdfld

搜完以i为根的子树,我们可以用两个桶分别表示:
1. now[0][x] 为i的子树中,所有能经过i的起点s,fl[s]=x的数量
2. now[1][x] 为i的子树中,所有能经过i的终点t,len-fl[t]=x的数量

则x的节点的答案为now[0][w[x]+fl[x]]-搜完i的子树前的now[0][w[x]-fl[x]]+now[1][w[x]-fl[x]]-搜完i的子树前的now[1][w[x]-fl[x]]

Codes

#include<cstring>#include<cstdio>#define lim 100000000#define ad 600010 using namespace std;int to[ad*2],nex[ad*2],fir[ad],las[ad],w[ad],n,m,len;int data[ad],fl[ad],num[2][ad*2],top,f[20][ad],vfir[2][ad*2],vlas[2][ad*2],vnex[2][ad*2],sum[ad],vtot[2],vv[2][ad*2];bool bz[300000];void link(int x,int y){    top++;    to[top]=y;nex[top]=0;    if(fir[x])nex[las[x]]=top;else fir[x]=top;    las[x]=top;}void swap(int &a,int &b){int c=a;a=b;b=c;}void vlink(int x,int s,int v){    int a,b,c,d,e,f;    int k=++vtot[s];    vv[s][k]=v;    vnex[s][k]=0;    if(vfir[s][x])vnex[s][vlas[s][x]]=k;else vfir[s][x]=k;    vlas[s][x]=k;    a=x;b=s;c=v;    d=vv[s][k];    e=vfir[s][x];    f=vlas[s][x];}void work(int x){    int s1=num[0][fl[x]+w[x]+ad],s2=num[1][w[x]-fl[x]+ad];    for(int j=0;j<2;j++)        for(int i=vfir[j][x];i;i=vnex[j][i])        {            int xx=vv[j][i];            if(xx<=lim)num[j][xx]++;        }    for(int i=fir[x];i;i=nex[i])    {        if(bz[to[i]])continue;        bz[to[i]]=1;        work(to[i]);    }    for(int j=0;j<2;j++)        for(int i=vfir[j][x];i;i=vnex[j][i])        {            int xx=vv[j][i];            if(xx>lim)num[j][xx-lim]--;        }    sum[x]+=num[0][ad+fl[x]+w[x]]-s1;    sum[x]+=num[1][w[x]-fl[x]+ad]-s2;}int main(){    freopen("running.in","r",stdin);    freopen("running.out","w",stdout);    scanf("%d%d",&n,&m);    for(int i=1;i<n;i++)    {        int x,y;        scanf("%d%d",&x,&y);        link(x,y),link(y,x);    }    int h=0,t=1;    data[1]=1;    fl[1]=0;bz[1]=1;    while(h<t)    {        int now=data[++h];        for(int i=fir[now];i;i=nex[i])        {            int x=to[i];            if(!bz[x])            {                bz[x]=1;                f[0][x]=now;                fl[x]=fl[now]+1;                data[++t]=x;            }        }    }    for(int i=1;i<=n;i++)scanf("%d",&w[i]);    for(int j=1;j<20;j++)        for(int i=1;i<=n;i++)            if(fl[i]>=(1<<j))            {                f[j][i]=f[j-1][f[j-1][i]];            }    for(int i=1;i<=m;i++)    {        int s,t,lca,tx,ty,temp,co=0;        scanf("%d%d",&s,&t);        if(s==t)        {            if(w[s]==0)sum[s]++;            continue;        }        tx=s,ty=t;        if(fl[tx]>fl[ty])swap(tx,ty);        temp=fl[ty]-fl[tx];        while(temp)        {            if(temp&1)ty=f[co][ty];            temp>>=1;            co++;        }        if(tx==ty)        {            lca=tx;        }else        {            for(int j=19;j+1;j--)            {                if((1<<j)>fl[tx])continue;                if(f[j][ty]!=f[j][tx])                {                    tx=f[j][tx];                    ty=f[j][ty];                }            }            lca=f[0][tx];        }        len=fl[s]+fl[t]-fl[lca]*2;        if(w[lca]==fl[s]-fl[lca])sum[lca]++;        if(s!=lca)        {            vlink(s,0,ad+fl[s]);            vlink(lca,0,ad+fl[s]+lim);        }        if(t!=lca)        {            vlink(t,1,ad+len-fl[t]);            vlink(lca,1,ad+len-fl[t]+lim);        }    }    memset(bz,0,sizeof(bz));    bz[1]=1;    work(1);    for(int i=1;i<=n;i++)printf("%d ",sum[i]);}
0 0
原创粉丝点击