天天爱跑步
(File IO): input:running.in output:running.out
Time Limits: 2s Memory Limits: 512MB
Description
Input
Output
Sample Input
Sample Input1:
6 3
2 3
1 2
1 4
4 5
4 6
0 2 5 1 2 3
1 5
1 3
2 6
Sample Input2:
5 3
1 2
2 3
2 4
1 5
0 1 0 3 0
3 1
1 4
5 5
Sample Output
Sample Output1:
2 0 0 1 1 1
Sample Output2:
1 2 1 0 1
Hint
Data Constraint
解题思路
以1为根遍历一遍,求出每一个点的的层数fl[i]
对于每一对s,t都会有他们的lca,则s到t的长度len为fl[s]+fl[t]-2fl[lca]我们可以分为s->lca,lca->t考虑:
对于路径s->lca的点d如图①,在第w[d]个时间点上到达需满足
wd+fld=fls
对于路径lca->t的点d如图②,在第w[d]个时间点上到达需满足
fld−fllca+fls−fllca=wd
||
len−flt=wd−fld
搜完以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]);
}