这一道题是一道典型的由部分分推正解的题。
对于子链,所有si=1,所有ti=1的情况,经过思考,会发现正解只需要将所有的路径拆成两条链,两种情况分别跑一次,把结果加起来即可。
#include<cstdio>
#include<cstring>
#include<iostream>
#include<vector>
#define il inline
#define dg isdigit
#define gc getchar()
using namespace std;
template<typename T>il void read(T &x){
x=0;int f=0;char s=gc;
while(!dg(s))f|=s=='-',s=gc;
while( dg(s))x=x*10+s-48,s=gc;
x=f?-x:x;
}
const int N=3e5+10;
struct edge{
int v,nxt;
}e[N<<1];int tot,last[N];
il void Addedge(int u,int v){
e[++tot]=(edge){v,last[u]};
e[++tot]=(edge){u,last[v]};
last[u]=tot-1,last[v]=tot;
}
int n,m,w[N],d[N];
int fa[N],ff[N],vis[N],lca[N];
vector<int>query[N],query_id[N];
il void Addquery(int u,int v,int id){
query[u].push_back(v),query_id[u].push_back(id);
query[v].push_back(u),query_id[v].push_back(id);
}
int findfa(int x){
return x==fa[x]?x:fa[x]=findfa(fa[x]);
}
struct node{
int x,y;
}b[N];
void Tarjan(int u){
vis[u]=1;
for(int i=last[u];i;i=e[i].nxt){
int v=e[i].v;
if(vis[v])continue;
d[v]=d[u]+1;
Tarjan(v);
fa[v]=u;ff[v]=u;
}
for(int i=0;i<query[u].size();i++){
int v=query[u][i],id=query_id[u][i];
if(vis[v]==2){
int tt=findfa(v);
if(d[lca[id]]<d[tt])lca[id]=tt;
}
}
vis[u]=2;
}
int ans[N],c1[N<<1],c2[N<<1];
vector<int>a1[N],a2[N],b1[N],b2[N];
void dfs(int u){
int val1=c1[w[u]+d[u]],val2=c2[w[u]-d[u]+n];
for(int i=last[u];i;i=e[i].nxt){
int v=e[i].v;
if(v!=ff[u])dfs(v);
}
for(int i=0;i<a1[u].size();i++)c1[a1[u][i]]++;
for(int i=0;i<a2[u].size();i++)c1[a2[u][i]]--;
for(int i=0;i<b1[u].size();i++)c2[b1[u][i]+n]++;
for(int i=0;i<b2[u].size();i++)c2[b2[u][i]+n]--;
ans[u]+=c1[d[u] + w[u]]-val1+c2[w[u]-d[u]+n]-val2;
}
int main(){
read(n),read(m);
for(int i=1,x,y;i<n;i++){
read(x),read(y);
Addedge(x,y);
}
for(int i=1;i<=n;i++)read(w[i]);
for(int i=1;i<=n;i++)
fa[i]=i,vis[i]=0;
for(int i=1,S,T;i<=m;i++){
read(S),read(T);
b[i].x=S,b[i].y=T;
if(S==T)lca[i]=S;
else{
Addquery(S,T,i);
lca[i]=0;
}
}
d[1]=1;Tarjan(1);
for(int i=1;i<=m;i++){
int x=b[i].x,y=b[i].y,z=lca[i];
a1[x].push_back(d[x]);
a2[ff[z]].push_back(d[x]);
b1[y].push_back(d[x]-2*d[z]);
b2[z].push_back(d[x]-2*d[z]);
}
dfs(1);
for(int i=1;i<=n;i++)printf("%d ",ans[i]);
return 0;
}