正题
题目链接:https://www.luogu.org/problemnew/show/P1600
题目大意
一棵nnn个点的树,通过每条边需要时间为1。有mmm个玩家从SiS_iSi跑到TiT_iTi(不停留,跑完之后马上消失)。然后对于第iii个点求第wiw_iwi刻停留在改点的玩家数量。
解题思路
对于每条路径我们拆分成两段,算是树上差分的一个变形
- 自S−>lcaS->lcaS−>lca,然后当该路径上一个点满足depi+wi=depSdep_i+w_i=dep_Sdepi+wi=depS则经过改点。
对于这种情况,我们用cnticnt_icnti表示起点为iii的人个数,VsiVs_iVsi表示lcalcalca在iii点的路径的起点深度集合。然后用vupivup_ivupi表示目前depS=idep_S=idepS=i的路径个数 - 自lca−>Elca->Elca−>E,然后当改点上一个点满足depi−wi=2∗deplca−depsdep_i-w_i=2*dep_{lca}-dep_sdepi−wi=2∗deplca−deps则经过改点。
为了方便陈述,我们定义num=2∗deplca−depsnum=2*dep_{lca}-dep_snum=2∗deplca−deps
对于这种情况,我们用cnt2icnt2_icnt2i表示终点为iii的路径numnumnum集合,VtiVt_iVti表示lcalcalca在iii点的路径的numnumnum集合。然后用vdownivdown_ivdowni表示目前num=inum=inum=i的路径个数
然后就完成了,不过要注意depi−widep_i-w_idepi−wi可能为负数所以我们需要加上一个大整数NNN。(PascalPascalPascal就莫得问题了)
codecodecode
#include<cstdio>
#include<algorithm>
#include<queue>
#include<cmath>
#include<vector>
using namespace std;
const int N=310000;
struct line{int to,next;
}a[N*5];
int tot,n,m,ls[N],dep[N],f[N][30];
int vup[4*N],vdown[4*N],cnt[N],T,ans[N],w[N];
vector<int> Vs[N],Vt[N],cnt2[N];
queue<int> q;
inline int read()
{int X=0,w=0; char c=0;while(c<'0'||c>'9') {w|=c=='-';c=getchar();}while(c>='0'&&c<='9') X=(X<<3)+(X<<1)+(c^48),c=getchar();return w?-X:X;
}
inline void addl(int x,int y)
{a[++tot].to=y;a[tot].next=ls[x];ls[x]=tot;
}
inline void bfs(int s)
{q.push(s);dep[s]=1;while(!q.empty()){int x=q.front();q.pop();for (int i=ls[x];i;i=a[i].next){int y=a[i].to;if (dep[y]) continue;q.push(y);f[y][0]=x;dep[y]=dep[x]+1;}}T=(int)(log(n)/log(2))+1;for (int j=1;j<=T;j++)for (int i=1;i<=n;i++)f[i][j]=f[f[i][j-1]][j-1];
}
inline int LCA(int x,int y)
{if (dep[x]>dep[y]) swap(x,y);for (int i=T;i>=0;i--)if (dep[f[y][i]]>=dep[x]) y=f[y][i];if (x==y) return x;for (int i=T;i>=0;i--)if (f[y][i]!=f[x][i]) {x=f[x][i];y=f[y][i];}return f[x][0];
}
void dfs(int x,int fa)
{int nup=dep[x]+w[x]+N,ndown=dep[x]-w[x]+N;int last=vup[nup]+vdown[ndown];vup[dep[x]+N]+=cnt[x];for(int i=0;i<cnt2[x].size();i++)vdown[cnt2[x][i]+N]++;for(int i=0;i<Vs[x].size();i++)vup[Vs[x][i]+N]--;for(int i=0;i<Vt[x].size();i++)vdown[Vt[x][i]+N]--;for(int i=ls[x];i;i=a[i].next){int y=a[i].to;if(y==fa) continue;dfs(y,x);}ans[x]+=vup[dep[x]+w[x]+N]+vdown[dep[x]-w[x]+N]-last;
}
int main()
{n=read();m=read();for(int i=1;i<n;i++){int x,y;x=read();y=read();addl(x,y);addl(y,x);}for(int i=1;i<=n;i++)w[i]=read();bfs(1);for(int i=1;i<=m;i++){int s,t;s=read();t=read();int lca=LCA(s,t);cnt[s]++;Vs[f[lca][0]].push_back(dep[s]);cnt2[t].push_back(2*dep[lca]-dep[s]);Vt[lca].push_back(2*dep[lca]-dep[s]);}dfs(1,1);for(int i=1;i<=n;i++)printf("%d ",ans[i]);
}