首先可以初步判断这个题肯定要计算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;
}

最后吐槽一下我到现在还没过2016年的毒瘤优秀数据