1. 程式人生 > >bzoj4573: [Zjoi2016]大森林

bzoj4573: [Zjoi2016]大森林

mic ostream math ide microsoft ios ring tar bzoj

傳送門

辣雞抄題解選手。

發現對於詢問,每棵樹只要把詢問的兩個點長在該長的位置了,它多長了些什麽點,包括不該長的點都無所謂。那麽讓每棵樹先長完了再詢問就好。、

也就是說問的是有n棵樹,每次讓所有樹長出一個節點,一開始都從1開始長,然後會修改一個區間的樹的長的位置。

先讓所有節點長出來,

給每個更換生長點的操作建一個權值為0的虛點,所有節點就先往它之前的最後一個虛點上長。然後把虛點按前後一個個串起來。

離線所有操作,然後從第左到右處理每棵樹。

每個虛點生效的是一段區間l~r,在l的時候虛點開始生效,就把它切下來接到它該接的實點上,在r+1的時候虛點失效,就把它切下來接回它的上一個虛點上,說明這個虛點上面長的點真正該長的地方是它的上一個虛點接的地方,或者上一個點也失效了接到前面去,就是前面某個地方,總會到達一個它該長的地方。

然後求兩點距離時不能直接求,需要通過lca,因為存在虛點,若兩個點的lca是一個虛點,他們真正的lca其實是虛點的某個祖先,直接算路徑就會算少,而求lca可以避免這個問題。

方法是access(x),再access(y),最後一次虛邊邊實邊的x就是lca。

技術分享圖片
//Achen
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<vector>
#include<cstdio>
#include<queue>
#include
<cmath> const int N=4e5+7; typedef long long LL; using namespace std; int n,m,v[N],ch[N][2],p[N],sum[N],sz[N],ans[N]; template<typename T>void read(T &x) { char ch=getchar(); x=0; T f=1; while(ch!=-&&(ch<0||ch>9)) ch=getchar(); if(ch==-) f=-1,ch=getchar();
for(;ch>=0&&ch<=9;ch=getchar()) x=x*10+ch-0; x*=f; } #define lc ch[x][0] #define rc ch[x][1] int isroot(int x) { return (ch[p[x]][0]!=x&&ch[p[x]][1]!=x); } void update(int x) { sum[x]=v[x]+sum[lc]+sum[rc]; } void rotate(int x) { int y=p[x],z=p[y],l=(x==ch[y][1]),r=l^1; if(!isroot(y)) ch[z][y==ch[z][1]]=x; p[x]=z; ch[y][l]=ch[x][r]; p[ch[x][r]]=y; ch[x][r]=y; p[y]=x; update(y); update(x); } void splay(int x) { for(;!isroot(x);rotate(x)) { int y=p[x],z=p[y]; if(!isroot(y)) ((x==ch[y][1])^(y==ch[z][1]))?rotate(x):rotate(y); } } int access(int x) { int t=0; for(;x;x=p[t=x]) { splay(x); rc=t; update(x); } return t; } void lik(int x,int y) { splay(x); p[x]=y; } void cut(int x) { access(x); splay(x); p[lc]=0; lc=0; update(x); } int qry(int x,int y) { int rs=0; access(x); splay(x); rs+=sum[x]; int t=access(y); splay(y); rs+=sum[y]; access(t); splay(t); rs-=2*sum[t]; return rs; } struct node { int pos,op,x,y; node(){} node(int pos,int op,int x,int y):pos(pos),op(op),x(x),y(y){} friend bool operator <(const node&A,const node&B) { return A.pos<B.pos||(A.pos==B.pos&&A.op<B.op); } }q[N]; int tot,last,id[N],idd,cnt,L[N],R[N],qs; void newnode(int x) { tot++; v[tot]=x; sum[tot]=x; } int main() { #ifdef DEBUG freopen(".in","r",stdin); freopen(".out","w",stdout); #endif read(n); read(m); newnode(1); idd=1; L[1]=1; R[1]=n; id[1]=1; newnode(0); last=2; lik(2,1); for(int ti=1;ti<=m;ti++) { int o,l,r,x,u,v; read(o); if(o==0) { read(l); read(r); newnode(1); L[++idd]=l; R[idd]=r; id[idd]=tot; q[++cnt]=node(1,ti-m,tot,last); } else if(o==1) { read(l); read(r); read(x); l=max(l,L[x]); r=min(r,R[x]); if(l<=r) { newnode(0); lik(tot,last); q[++cnt]=node(l,ti-m,tot,id[x]); q[++cnt]=node(r+1,ti-m,tot,last); last=tot; } } else { read(x); read(u); read(v); q[++cnt]=node(x,++qs,id[u],id[v]); } } sort(q+1,q+cnt+1); for(int i=1,j=1;i<=n;i++) { for(;j<=cnt&&q[j].pos==i;j++) { if(q[j].op<=0) { cut(q[j].x); lik(q[j].x,q[j].y); } else ans[q[j].op]=qry(q[j].x,q[j].y); } } for(int i=1;i<=qs;i++) printf("%d\n",ans[i]); return 0; } /* 5 5 0 1 5 1 2 4 2 0 1 4 2 1 1 3 2 2 1 3 1 3 0 1 1 0 1 1 2 1 2 3 */
View Code

bzoj4573: [Zjoi2016]大森林