P1600-天天爱跑步【LCA,桶,树上差分】

it2022-05-09  20

正题

题目链接:https://www.luogu.org/problemnew/show/P1600


题目大意

一棵 n n n个点的树,通过每条边需要时间为1。有 m m m个玩家从 S i S_i Si跑到 T i T_i Ti(不停留,跑完之后马上消失)。然后对于第 i i i个点求第 w i w_i wi刻停留在改点的玩家数量。


解题思路

对于每条路径我们拆分成两段,算是树上差分的一个变形

S − > l c a S->lca S>lca,然后当该路径上一个点满足 d e p i + w i = d e p S dep_i+w_i=dep_S depi+wi=depS则经过改点。 对于这种情况,我们用 c n t i cnt_i cnti表示起点为 i i i的人个数, V s i Vs_i Vsi表示 l c a lca lca i i i点的路径的起点深度集合。然后用 v u p i vup_i vupi表示目前 d e p S = i dep_S=i depS=i的路径个数自 l c a − > E lca->E lca>E,然后当改点上一个点满足 d e p i − w i = 2 ∗ d e p l c a − d e p s dep_i-w_i=2*dep_{lca}-dep_s depiwi=2deplcadeps则经过改点。 为了方便陈述,我们定义 n u m = 2 ∗ d e p l c a − d e p s num=2*dep_{lca}-dep_s num=2deplcadeps 对于这种情况,我们用 c n t 2 i cnt2_i cnt2i表示终点为 i i i的路径 n u m num num集合, V t i Vt_i Vti表示 l c a lca lca i i i点的路径的 n u m num num集合。然后用 v d o w n i vdown_i vdowni表示目前 n u m = i num=i num=i的路径个数

然后就完成了,不过要注意 d e p i − w i dep_i-w_i depiwi可能为负数所以我们需要加上一个大整数 N N N。( P a s c a l Pascal Pascal就莫得问题了)


c o d e code code

#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]); }

最新回复(0)