首先可以初步判断这个题肯定要计算LCA,我们、就写个简单的倍增只会这个吧,使用链式前向星存储边。
选择1号结点开始dfs
dfs过程中计算up[ ][ ]数组(up[x][i]表示 x 结点的 2^i代祖先是谁)和deep[ ]数组(deep[x]表示结点 x 在树中的深度)
然后我们不从运动员入手,而是枚举观察员。看看哪些结点会为这个观察员i做贡献(刚好在wi秒跑到他这儿)。
大头戏来了
AC代码
#include<algorithm>
#include<bitset>
#include<cctype>
#include<cmath>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<list>
#include<map>
#include<queue>
#include<set>
#include<stack>
#include<string>
#include<typeinfo>
#include<vector>
#define maxn 900000//本蒟蒻到现在都想不通为什么要开这么大
using namespace std;
struct node1
{
int begin,end,lca,len;
}p[maxn];
struct node2
{
int next,to;
}q[maxn*2];
struct node3
{
int nxt,v;
}q1[maxn*4];
struct node4
{
int ct1,ct2;
}o[maxn*2];//本蒟蒻觉得结构体好理解就写了四个
//当然大佬们的思维肯定不需要
int n, m,cnt,cnt1,val[maxn];
int first[maxn],ans[maxn];
int ins1[maxn],del1[maxn],ins2[maxn],del2[maxn];
int deep[maxn],up[maxn][20];//最重要的的两个数组
inline void add(int a,int b)
{
q[++cnt].next=first[a];
q[cnt].to=b;
first[a]=cnt;
}//链式前向星存边
inline void add1(int a,int b,int c)
{
q1[++cnt1].nxt=ins1[a];
q1[cnt1].v=c;
ins1[a]=cnt1;
q1[++cnt1].nxt=del1[b];
q1[cnt1].v=c;
del1[b]=cnt1;
}//链式前向星存边
inline void add2(int a,int b,int c)
{
q1[++cnt1].nxt=ins2[a];
q1[cnt1].v=c;
ins2[a]=cnt1;
q1[++cnt1].nxt=del2[b];
q1[cnt1].v=c;
del2[b]=cnt1;
}//链式前向星存边
void dfs(int x)
{
for(int i=1;(1<<i)<=deep[x];i++)
up[x][i]=up[up[x][i-1]][i-1];
for(int i=first[x];i;i=q[i].next)
{
if(q[i].to==up[x][0]) continue;
up[q[i].to][0]=x;
deep[q[i].to]=deep[x]+1;
dfs(q[i].to);
}
}//建树,预处理fa[][]数组, 计算deep[]数组
inline void dfs1(int x)
{
ans[x]=-o[deep[x]+val[x]].ct1-o[deep[x]-val[x]+n].ct2;
for(int i=first[x];i;i=q[i].next)
{
if(q[i].to==up[x][0]) continue;
dfs1(q[i].to);
}
for(int i=ins1[x];i;i=q1[i].nxt)
o[q1[i].v].ct1++;
for(int i=del1[x];i;i=q1[i].nxt)
o[q1[i].v].ct1--;
for(int i=ins2[x];i;i=q1[i].nxt)
o[q1[i].v+n].ct2++;
for(int i=del2[x];i;i=q1[i].nxt)
o[q1[i].v+n].ct2--;
ans[x]+=o[deep[x]+val[x]].ct1+o[deep[x]-val[x]+n].ct2;
}//找“贡献”
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 a,b;
scanf("%d%d",&a,&b);
add(a,b),add(b,a);
}
deep[1]=1;
dfs(1);
for(int i=1;i<=n;i++)
scanf("%d",&val[i]);
for(int i=1;i<=m;i++)
scanf("%d%d",&p[i].begin,&p[i].end);
for(int i=1;i<=m;i++)
{
int x=p[i].begin,y=p[i].end;
if(deep[x]<deep[y])
swap(x,y);
if(deep[x]!=deep[y])
for(int i=18;i>=0;i--)
if(deep[up[x][i]]>=deep[y])
x=up[x][i];
if(x!=y)
{
for(int j=18;j>=0;j--)
if(up[x][j]!=up[y][j])
x=up[x][j],y=up[y][j];
x=up[x][0];
}
p[i].lca=x;
p[i].len=deep[p[i].begin]-deep[x]+deep[p[i].end]-deep[x];
}//ICA(x和y的最近公共祖先) 实在不想再开函数了,而且这样显得主函数没那么空虚
for(int i=1;i<=m;i++)
{
add1(p[i].begin,up[p[i].lca][0],deep[p[i].begin]);
add2(p[i].end,p[i].lca,deep[p[i].end]-p[i].len);
}
dfs1(1);
for(int i=1;i<=n;i++)
printf("%d ",ans[i]);//完美输出
//终于结束了 QAQ
return 0;
} 
京公网安备 11010502036488号