題意:
給你一個個點的森林,起初每棵樹都只有一個點,這個點是生長節點,長出的兒子會接在生長節點上。有次操作。要支持以下操作:第一個操作是讓一個區間的樹的生長節點全長出一個兒子,兒子的編號是這個位置的點現在的數量。第二個操作是讓一個區間的生長節點都變成某一個點。第三個操作是詢問第棵樹上點到點的距離。.
題解:
一道很神仙的題,我也不知道我懂了沒有,我更不知道我能不能講明白。
這個題的思想是,我們每次操作一個區間的樹,這樣會有一些區間的樹形態相同,所以我們考慮能不能不每一棵樹都建出來,用一個東西來維護許多LCT。我也不知道該怎麼說了,也不知道是怎麼想到的,反正是個很神仙的想法。
我們把詢問離線,然後對換生長節點和詢問操作按照操作位置排序,位置相同的先處理換生長節點。我們把一個換生長節點的操作拆成兩個,一個是在處出現這個操作,一個是在處這個影響消失。我們考慮建LCT,然後LCT上分兩類點,一類點是有權值的一類點是沒有權值的。沒有權值的點表示的是換生長節點的操作,有權值的點表示的是區間生長出一個葉子的操作。我們一開始建一個根節點,表示一開始所有的樹一開始都有一個點,這個根節點的權值是。然後把所有的表示操作的點連成一串,連的方法是,我們連向上一個出現的操作。然後我們對於每一個操作,我們也向上一個出現的操作連邊。
我們排序之後按照位置順序開始做。先處理修改生長節點操作。如果是一個操作,我們就把它連到修改後的那個節點,如果是一個操作,那麼就改回到原來鏈接的那個它前面的一個操作節點。對於詢問,我們就直接用兩個點到根的深度之和減去兩倍LCA的深度即可。用LCT求LCA的方法是我們access其中的一個點,然後再access另一個點,在第二個點access的過程中,最後一次虛實邊切換的時候的那個點就是LCA。
然後這個題由於最好保持樹的父子關係不變,所以沒有makeroot,而且也沒有子樹信息詢問,可以不用makeroot。
下面附上幾張網上用來解釋這個樣例構建LCT的過程的圖片。
五個操作排序後這樣子的:
0 1 5
0 1 4
2 1 1 3
1 2 4 2
2 2 1 3
講解差不多就到這裏。複雜度是。
代碼:
#include <bits/stdc++.h>
using namespace std;
int n,m,f[600010],c[600010][2],s[600010],val[600010],rt,cnt;
int l[600010],r[600010],id[600010],num,shu,qwq,ans[600010];
struct node
{
int opt,pos,x,y;
}a[300010];
inline int read()
{
int x=0;
char s=getchar();
while(s>'9'||s<'0')
s=getchar();
while(s>='0'&&s<='9')
{
x=x*10+s-'0';
s=getchar();
}
return x;
}
inline int cmp(node x,node y)
{
if(x.pos==y.pos)
return x.opt<y.opt;
else
return x.pos<y.pos;
}
inline int nroot(int x)
{
return c[f[x]][0]==x||c[f[x]][1]==x;
}
inline void pushup(int x)
{
s[x]=val[x]+s[c[x][0]]+s[c[x][1]];
}
inline void rotate(int x)
{
int y=f[x],z=f[y],k=c[y][1]==x,w=c[x][!k];
if(nroot(y))
c[z][c[z][1]==y]=x;
c[x][!k]=y;
c[y][k]=w;
if(w)
f[w]=y;
f[y]=x;
f[x]=z;
pushup(y);
pushup(x);
}
inline void splay(int x)
{
while(nroot(x))
{
int y=f[x],z=f[y];
if(nroot(y))
{
if(c[y][1]==x ^ c[z][1]==y)
rotate(x);
else
rotate(y);
}
rotate(x);
}
pushup(x);
}
inline int access(int x)
{
int y=0;
while(x)
{
splay(x);
c[x][1]=y;
if(y)
f[y]=x;
pushup(x);
y=x;
x=f[x];
}
return y;
}
inline void link(int x,int y)
{
access(x);
splay(x);
f[x]=y;
}
inline void cut(int x)
{
access(x);
splay(x);
f[c[x][0]]=0;
c[x][0]=0;
pushup(x);
}
int main()
{
n=read();
m=read();
l[1]=1;
r[1]=n;
s[1]=1;
val[1]=1;
id[1]=1;
rt=2;
link(2,1);
cnt=2;
num=1;
for(int i=1;i<=m;++i)
{
int opt=read();
if(opt==0)
{
id[++num]=++cnt;
link(cnt,rt);
int x=read(),y=read();
l[num]=x;
r[num]=y;
val[cnt]=1;
s[cnt]=1;
}
else if(opt==1)
{
int x=read(),y=read(),z=read();
x=max(x,l[z]);
y=min(y,r[z]);
if(x>y)
continue;
++cnt;
link(cnt,rt);
a[++shu].opt=-1;
a[shu].pos=x;
a[shu].x=cnt;
a[shu].y=id[z];
a[++shu].opt=-1;
a[shu].pos=y+1;
a[shu].x=cnt;
a[shu].y=rt;
rt=cnt;
}
else
{
int x=read(),y=read(),z=read();
a[++shu].pos=x;
a[shu].x=id[y];
a[shu].y=id[z];
a[shu].opt=++qwq;
}
}
sort(a+1,a+shu+1,cmp);
for(int i=1;i<=shu;++i)
{
if(a[i].opt>0)
{
int res=0;
access(a[i].x);
splay(a[i].x);
res+=s[a[i].x];
int ji=access(a[i].y);
splay(a[i].y);
res+=s[a[i].y];
access(ji);
splay(ji);
res-=2*s[ji];
ans[a[i].opt]=res;
}
else
{
cut(a[i].x);
link(a[i].x,a[i].y);
}
}
for(int i=1;i<=qwq;++i)
printf("%d\n",ans[i]);
return 0;
}