天天爱跑步
一道:树上差分+LCA+桶的题
说实话,这道题放在D1T2就是非常不合理的。然而CCF就是放了,并且还是能依靠CSP捞钱,你也必须交钱参加比赛。这个社会是多么的不公啊!闲扯结束
显然如果对每条路径都进行一次处理,复杂度不对。考虑对路径进行一次预处理,然后进行统一的计算答案。我们发现当一条路径对某一个点P产生贡献时满足这个条件:
1.当\(P\)在该路径的\(S\)与\(LCA\)之间时 \(dep[S]-dep[P]=watch[P]\) 移一下项为\(dep[S]=dep[P]+watch[P]\)那么该路径起点对P有贡献
2.当\(P\)在该路径的\(LCA\)与\(T\)之间时 \(dist[S,T]-watch[P]=dep[T]-dep[P]\) 移一下项\(dist[S,T]-dep[T]=watch[P]-dep[P]\)那么该路径终点对P有贡献
然后用一个全局桶维护这些贡献 当枚举到当前点的时候 将当前点作为终点和起点的贡献加在桶里面。然后计算当前点的ans
细节:一个它只会受其子树的贡献,其他的贡献不会有的。如何处理?在开始遍历这个点的时候用\(ad1,ad2\)来存储已经存在的桶里面的值 然后遍历子树 当又返回到当前节点的时候 计算当前节点的答案。显然当前节点的答案为\(ans[x]+=bas1[watch[x]+dep[x]]-ad1+bas2[watch[x]-dep[x]+maxn]-ad2\)
注意到我们对\(bas2\)的计算的时候加了一个\(maxn\) ,其实原因很显然 \(watch[x]-dep[x]\)有可能小于零
还有就是当遍历完当前点 应该将以当前点为LCA的路径的影响全部消除。因为如果以当前点为LCA,显然不会对当前点的父亲及祖先产生影响,应该减掉
然后就是代码了QAQ 我是用的邻接表存储的以当前节点为终点的路径编号,以及以当前节点为LCA的路径编号
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#define int long long
using namespace std;
const int maxn=500010;
int read(){
int x=0,f=1;char ch=getchar();
while(ch<'0' || ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0' && ch<='9'){x=x*10+ch-'0';ch=getchar();}
return x*f;
}
int n,m,fir[maxn],nxt[maxn<<1],to[maxn<<1],tot=1,watch[maxn],fa[maxn][25];
int st[maxn],ed[maxn],stt[maxn],dist[maxn],ans[maxn],dep[maxn];
int fir1[maxn],nxt1[maxn<<1],to1[maxn<<1],tot1,fir2[maxn],nxt2[maxn<<1],to2[maxn<<1],tot2;
void add(int x,int y){nxt[++tot]=fir[x];fir[x]=tot;to[tot]=y;}
void dfs1(int x){
dep[x]=dep[fa[x][0]]+1;
for(int i=0;i<=20;i++)
fa[x][i+1]=fa[fa[x][i]][i];
for(int i=fir[x];i;i=nxt[i]){
int y=to[i];if(y==fa[x][0]) continue;
fa[y][0]=x;dfs1(y);
}
}
int LCA(int x,int y){
if(dep[x]<dep[y]) swap(x,y);
for(int i=20;i>=0;i--){
if(dep[fa[x][i]]>=dep[y]) x=fa[x][i];
if(x==y) return x;
}
for(int i=20;i>=0;i--){
if(fa[x][i]!=fa[y][i]){
x=fa[x][i];y=fa[y][i];
}
}
return fa[x][0];
}
void add1(int x,int y){nxt1[++tot1]=fir1[x];fir1[x]=tot1;to1[tot1]=y;}
void add2(int x,int y){nxt2[++tot2]=fir2[x];fir2[x]=tot2;to2[tot2]=y;}
int bas1[maxn<<1],bas2[maxn<<1],ad1,ad2;
void dfs2(int x){
ad1=bas1[watch[x]+dep[x]];ad2=bas2[watch[x]-dep[x]+maxn];
for(int i=fir[x];i;i=nxt[i]){
int y=to[i];if(y==fa[x][0]) continue;
dfs2(y);
}
bas1[dep[x]]+=stt[x];
for(int i=fir1[x];i;i=nxt1[i]){
int y=to1[i];
bas2[dist[y]-dep[ed[y]]+maxn]++;
}
ans[x]+=bas1[watch[x]+dep[x]]-ad1+bas2[watch[x]-dep[x]+maxn]-ad2;
for(int i=fir2[x];i;i=nxt2[i]){
int y=to2[i];
bas1[dep[st[y]]]--;
bas2[dist[y]-dep[ed[y]]+maxn]--;
}
}
signed main(){
n=read();m=read();
for(int i=1,x,y;i<=n-1;i++){
x=read();y=read();
add(x,y);add(y,x);
}
for(int i=1;i<=n;i++) watch[i]=read();
dep[1]=1;
dfs1(1);
for(int i=1,x,y,lca;i<=m;i++){
x=read();y=read();
lca=LCA(x,y);st[i]=x;ed[i]=y;
dist[i]=dep[x]+dep[y]-2*dep[lca];
stt[x]++;add1(y,i);add2(lca,i);
if(dep[lca]+watch[lca]==dep[x]) ans[lca]--;
}
dfs2(1);
for(int i=1;i<=n;i++)
printf("%lld ",ans[i]);
}