思路:
题目所要求的是每一个观测点能够看到的人的个数,所以这个观测点首先必须要在这条路径内。其次就是这个观测点和路径起点的距离要等于
,为了便于操作把这棵树转化成1为根的有根树,然后每一条路径就是一条折线。我们把每个点满足它可以观测到的路径的条件转化为只和路径相关,设路径起点为
,终点为
,观测点为
,一条路通过lca分开成了两条路之后,对于上升的部分要满足这个式子:
,下降的部分则要满足这个式子:
。
那么题目就可以看成对于每一个观测点,分两次来处理每条路径上升的部分和下降的部分,对于每一次处理,求覆盖它的并且等式左边的值都是同一个定值的个数。我们通过树上差分来得到每一个点所有的覆盖它的路径,并且用一个桶来存下这些路径等式右边的值,桶的维护复杂度是线性的。
注意到我们只可以开一个桶,而树上差分是求整个子树内的状态叠加,所以这里改成按照dfs顺序依次差分,查询答案只需要计算子树访问前后的差值就好了。
#include<bits/stdc++.h>
#define REP(i,a,b) for(int i=a;i<=b;++i)
typedef long long ll;
using namespace std;
void File(){
freopen("uoj261.in","r",stdin);
freopen("uoj261.out","w",stdout);
}
template<typename T>void read(T &_){
T __=0,mul=1; char ch=getchar();
while(!isdigit(ch)){
if(ch=='-')mul=-1;
ch=getchar();
}
while(isdigit(ch))__=(__<<1)+(__<<3)+(ch^'0'),ch=getchar();
_=__*mul;
}
const int maxn=3e5+10;
const int maxm=3e5+10;
int n,m,S[maxm],T[maxm],w[maxn],st[maxn][30],dep[maxn];
int beg[maxn],las[maxn<<1],to[maxn<<1],cnte=1;
int Len[maxn],tona[maxn<<1],tonb[maxn<<1],ans[maxn];
vector<int>taga[maxn],tagb[maxn];
void add(int u,int v){
las[++cnte]=beg[u]; beg[u]=cnte; to[cnte]=v;
las[++cnte]=beg[v]; beg[v]=cnte; to[cnte]=u;
}
void dfs(int u,int f){
st[u][0]=f; dep[u]=dep[f]+1;
for(int i=beg[u];i;i=las[i]){
if(to[i]==f)continue;
dfs(to[i],u);
}
}
int Log(int x){return floor(log(x)/log(2));}
int find(int u,int v){
if(dep[v]>dep[u])swap(u,v);
while(dep[u]!=dep[v])u=st[u][Log(dep[u]-dep[v])];
if(u==v)return u;
for(int k=25;k>=0 && u!=v;--k)
if(st[u][k] && st[v][k] && st[u][k]!=st[v][k])
u=st[u][k],v=st[v][k];
return st[u][0];
}
void solve(int u){
ans[u]-=tona[w[u]+dep[u]]+tonb[dep[u]-w[u]+maxn];
int siza=taga[u].size()-1,sizb=tagb[u].size()-1;
REP(i,0,siza)if(taga[u][i]>0)++tona[taga[u][i]];
else --tona[-taga[u][i]];
REP(i,0,sizb)if(tagb[u][i]>0)++tonb[tagb[u][i]];
else --tonb[-tagb[u][i]];
for(int i=beg[u];i;i=las[i]){
if(to[i]==st[u][0])continue;
solve(to[i]);
}
ans[u]+=tona[w[u]+dep[u]]+tonb[dep[u]-w[u]+maxn];
}
void init(){
read(n); read(m);
int u,v;
REP(i,1,n-1)read(u),read(v),add(u,v);
REP(i,1,n)read(w[i]);
dfs(1,0);
REP(i,1,26)REP(j,1,n){
if((1<<i)>=dep[j])continue;
st[j][i]=st[st[j][i-1]][i-1];
}
REP(i,1,m){
read(u); read(v);
int lca=find(u,v);
Len[i]=dep[u]+dep[v]-(dep[lca]<<1);
taga[u].push_back(dep[u]); taga[st[lca][0]].push_back(-dep[u]);
tagb[v].push_back(dep[v]-Len[i]+maxn); tagb[lca].push_back(-dep[v]+Len[i]-maxn);
}
}
int main(){
File();
init();
solve(1);
REP(i,1,n)printf("%d\n",ans[i]);
return 0;
}