P1600-天天爱跑步【LCA,桶,树上差分】
生活随笔
收集整理的這篇文章主要介紹了
P1600-天天爱跑步【LCA,桶,树上差分】
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
正題
題目鏈接:https://www.luogu.org/problemnew/show/P1600
題目大意
一棵nnn個點的樹,通過每條邊需要時間為1。有mmm個玩家從SiS_iSi?跑到TiT_iTi?(不停留,跑完之后馬上消失)。然后對于第iii個點求第wiw_iwi?刻停留在改點的玩家數量。
解題思路
對于每條路徑我們拆分成兩段,算是樹上差分的一個變形
對于這種情況,我們用cnticnt_icnti?表示起點為iii的人個數,VsiVs_iVsi?表示lcalcalca在iii點的路徑的起點深度集合。然后用vupivup_ivupi?表示目前depS=idep_S=idepS?=i的路徑個數
為了方便陳述,我們定義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]); }總結
以上是生活随笔為你收集整理的P1600-天天爱跑步【LCA,桶,树上差分】的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: P5135-painting【组合数学】
- 下一篇: 丑时是几点到几点钟啊 丑时的具体时间是几