日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

P3348-[ZJOI2016]大森林【LCT】

發布時間:2023/12/3 编程问答 35 豆豆
生活随笔 收集整理的這篇文章主要介紹了 P3348-[ZJOI2016]大森林【LCT】 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

正題

題目鏈接:https://www.luogu.com.cn/problem/P3348


題目大意

nnn棵樹開始只有一個編號為111的節點且為標記點。mmm次操作要求支持

  • l~rl\sim rlr的樹中的標記點下面加入一個新的編號的節點
  • l~rl\sim rlr的樹上的標記點改為xxx(如果沒有節點xxx就不操作)
  • 詢問第xxx棵樹上uuu點到vvv點的距離
  • 1≤n≤105,1≤m≤2×1051\leq n\leq 10^5,1\leq m\leq 2\times 10^51n105,1m2×105
    保證詢問合法


    解題思路

    保證詢問合法的話我們其實第一個操作理解為對所有樹都操作就可以了。主要是第二個操作,在線區間LCTLCTLCT看起來就很不可做,所以考慮離線。

    對于一個操作1lrx1\ l\ r\ x1?l?r?x它會對l?1l-1l?1lll的樹造成的影響是再往后直到下一個111操作之間所有的節點都會被接到不同的點下面。但是顯然暴力改接是不行的,我們可以考慮對于兩個111操作之間的000操作建立一個虛點下面鏈接的所有這個區間新建的點,然后每次就改接一個虛點就好了。

    然后需要注意的一些細節:因為根是固定的不能用splitsplitsplit,會破壞父子關系(好像在makeroot(1)makeroot(1)makeroot(1)回去可以,但是據說很慢?),所以要差分求到根節點的路徑長度。還要求lcalcalcaLCTLCTLCT上求lcalcalca的話就accessaccessaccessxxx再到yyy最后SplaySplaySplay的那個yyy就是lcalcalca了。

    還有因為如果沒有節點xxx就不操作,所以我們需要記錄一下每個點擁有的樹的區間然后取一個交集就好了。

    時間復雜度O(nlog?n)O(n\log n)O(nlogn)


    code

    #include<cstdio> #include<cstring> #include<algorithm> using namespace std; const int N=2e5+10; struct node{int x,l,r,id; }q[N],c[N]; int n,m,num,cnt,ct,qt; int L[N],R[N],ans[N],at[N]; struct LCT{int fa[N],t[N][2],siz[N],v[N];bool Nroot(int x){return fa[x]&&(t[fa[x]][0]==x||t[fa[x]][1]==x);}bool Direct(int x){return t[fa[x]][1]==x;}void PushUp(int x){siz[x]=siz[t[x][0]]+siz[t[x][1]]+v[x];return;}void Rotate(int x){int y=fa[x],z=fa[y];int xs=Direct(x),ys=Direct(y);int w=t[x][xs^1];if(Nroot(y))t[z][ys]=x;t[x][xs^1]=y;t[y][xs]=w;if(w)fa[w]=y;fa[y]=x;fa[x]=z;PushUp(y);PushUp(x);return;}void Splay(int x){while(Nroot(x)){int y=fa[x];if(!Nroot(y))Rotate(x);else if(Direct(x)==Direct(y))Rotate(y),Rotate(x);else Rotate(x),Rotate(x);}return;}int Access(int x){int y=0,px=x;for(;x;y=x,x=fa[x])Splay(x),t[x][1]=y,PushUp(x);Splay(px);return y;}void Link(int x,int y){Splay(x);fa[x]=y;return;}void Cut(int x){Access(x);fa[t[x][0]]=0;t[x][0]=0;PushUp(x);return;} }T; bool cmp(node x,node y) {return x.x<y.x;} int main() {scanf("%d%d",&n,&m);L[1]=cnt=at[1]=1;R[1]=n;T.Link(2,1);cnt=2;int last=2,num=1,aux=2;for(int i=1;i<=m;i++){int op,l,r,x;scanf("%d%d%d",&op,&l,&r);if(op==0){++num;at[num]=++cnt;T.v[cnt]=T.siz[cnt]=1;T.Link(cnt,aux);L[num]=l;R[num]=r;}else if(op==1){scanf("%d",&x);l=max(l,L[x]);r=min(r,R[x]);if(l>r)continue;++cnt;T.Link(cnt,aux);c[++ct]=(node){l,cnt,at[x]};c[++ct]=(node){r+1,cnt,aux,0};aux=cnt;}else{scanf("%d",&x);q[++qt]=(node){l,at[r],at[x],qt};}}sort(q+1,q+1+qt,cmp);sort(c+1,c+1+ct,cmp);for(int i=1,z=1;i<=qt;i++){int sum=0;while(z<=ct&&c[z].x<=q[i].x)T.Cut(c[z].l),T.Link(c[z].l,c[z].r),z++;T.Access(q[i].l);sum+=T.siz[q[i].l];int lca=T.Access(q[i].r);sum+=T.siz[q[i].r];T.Access(lca);sum-=2*T.siz[lca];ans[q[i].id]=sum;}for(int i=1;i<=qt;i++)printf("%d\n",ans[i]);return 0; } 創作挑戰賽新人創作獎勵來咯,堅持創作打卡瓜分現金大獎

    總結

    以上是生活随笔為你收集整理的P3348-[ZJOI2016]大森林【LCT】的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。