luogu P1600 天天愛跑步
阿新 • • 發佈:2018-11-08
void gist math str show getch 設有 wap print 為路徑長度(結束時間點),\(mid\)為到達\(lca\)的時間,在\(x\)的第一個線段樹的\(de_x\)處+1,在\(lca\)的第一個線段樹的\(mid+de_{lca}\)處-1,在y的第二個線段樹的\(len-de_y+n\)處+1,在\(fa_{lca}\)的第二個線段樹的\(mid-1-de_{fa_{lca}}+n\)處-1(不能出現負下標).dfs整棵樹,把\(x\)所有兒子的線段樹並起來,然後這個點的答案就是第一棵線段樹的\(w_x+de_x\)加第二棵線段樹的\(w_x-de_x+n\)的值
傳送門
1A此題暴祭
(下面記點\(x\)深度為\(de_x\),某個時間點記為\(w_x\))
首先,每條路徑是可以拆成往上和往下兩條路徑的
對於往上的路徑,假設有個人往上跑,\(w_y\)在點\(y\),那麽如果能對點\(x\)的觀察員產生貢獻,當且僅當\(w_x+de_x=w_y+de_y\)
對於往下的路徑,假設有個人往下跑,\(w_y\)在點\(y\),那麽如果能對點\(x\)的觀察員產生貢獻,當且僅當\(w_x-de_x=w_y-de_y\)
所以對於每個點開兩個線段樹,每個下表存\(w_x+de_x\)或\(w_x-de_x\)的點的個數,對於每條路徑(x,y),記\(len\)
我太傻了,這兩顆線段樹可以分開處理的,我放在一起處理了,空間爆炸,bzoj就過不去了qwq
#include<bits/stdc++.h> #define LL long long #define il inline #define re register #define db double #define eps (1e-5) using namespace std; const int N=300000+10; il LL rd() { LL x=0,w=1;char ch=0; while(ch<'0'||ch>'9') {if(ch=='-') w=-1;ch=getchar();} while(ch>='0'&&ch<='9') {x=(x<<3)+(x<<1)+(ch^48);ch=getchar();} return x*w; } int to[N<<1],nt[N<<1],hd[N],tot=1; il void add(int x,int y) { ++tot,to[tot]=y,nt[tot]=hd[x],hd[x]=tot; ++tot,to[tot]=x,nt[tot]=hd[y],hd[y]=tot; } int n,m,w[N],an[N],fa[N],sz[N],de[N],son[N],top[N]; void dfs1(int x) { sz[x]=1; for(int i=hd[x];i;i=nt[i]) { int y=to[i]; if(y==fa[x]) continue; fa[y]=x,de[y]=de[x]+1,dfs1(y),sz[x]+=sz[y]; if(sz[son[x]]<sz[y]) son[x]=y; } } void dfs2(int x,int ntp) { top[x]=ntp; if(son[x]) dfs2(son[x],ntp); for(int i=hd[x];i;i=nt[i]) { int y=to[i]; if(y==fa[x]||y==son[x]) continue; dfs2(y,y); } } il int glca(int x,int y) { while(top[x]!=top[y]) { if(de[top[x]]<de[top[y]]) swap(x,y); x=fa[top[x]]; } return de[x]<de[y]?x:y; } struct sgtree { int s[(N*3)*20],ch[(N*3)*20][2],rt[N],tt; sgtree(){tt=0;} il void inst(int o1,int o2,int x,int dt) { int l=1,r=n+n; s[o1]=s[o2]+dt; while(l<r) { int mid=(l+r)>>1; if(x<=mid) { ch[o1][0]=++tt,ch[o1][1]=ch[o2][1]; o1=ch[o1][0],o2=ch[o2][0]; r=mid; } else { ch[o1][0]=ch[o2][0],ch[o1][1]=++tt; o1=ch[o1][1],o2=ch[o2][1]; l=mid+1; } s[o1]=s[o2]+dt; } } int merge(int o1,int o2) { if(!o1||!o2) return o1+o2; int o=++tt; s[o]=s[o1]+s[o2]; ch[o][0]=merge(ch[o1][0],ch[o2][0]); ch[o][1]=merge(ch[o1][1],ch[o2][1]); return o; } int quer(int o,int l,int r,int lx) { if(!o) return 0; if(l==r) return s[o]; int mid=(l+r)>>1; if(lx<=mid) return quer(ch[o][0],l,mid,lx); else return quer(ch[o][1],mid+1,r,lx); } }S,T; il void dfs3(int x) { for(int i=hd[x];i;i=nt[i]) { int y=to[i]; if(y==fa[x]) continue; dfs3(y),S.rt[x]=S.merge(S.rt[x],S.rt[y]),T.rt[x]=T.merge(T.rt[x],T.rt[y]); } an[x]=S.quer(S.rt[x],1,n+n,w[x]+de[x])+T.quer(T.rt[x],1,n+n,w[x]-de[x]+n); } int main() { n=rd(),m=rd(); for(int i=1;i<n;i++) add(rd(),rd()); de[1]=1,dfs1(1),dfs2(1,1); for(int i=1;i<=n;i++) w[i]=rd(); while(m--) { int x=rd(),y=rd(),lca=glca(x,y),lth=de[x]+de[y]-(de[lca]<<1),mid=lth-de[y]+de[lca],la; la=S.rt[x],S.rt[x]=++S.tt,S.inst(S.rt[x],la,de[x],1); la=S.rt[lca],S.rt[lca]=++S.tt,S.inst(S.rt[lca],la,de[lca]+mid,-1); la=T.rt[y],T.rt[y]=++T.tt,T.inst(T.rt[y],la,lth-de[y]+n,1); la=T.rt[fa[lca]],T.rt[fa[lca]]=++T.tt,T.inst(T.rt[fa[lca]],la,mid-1-de[fa[lca]]+n,-1); } dfs3(1); for(int i=1;i<=n;i++) printf("%d ",an[i]); return 0; }
luogu P1600 天天愛跑步