[ZJOI2016]大森林(LCT)

题目描述

小Y家里有一个大森林,里面有n棵树,编号从1到n。一开始这些树都只是树苗,只有一个节点,标号为1。这些树都有一个特殊的节点,我们称之为生长节点,这些节点有生长出子节点的能力。

小Y掌握了一种魔法,能让第l棵树到第r棵树的生长节点长出一个子节点。同时她还能修改第l棵树到第r棵树的生长节点。她告诉了你她使用魔法的记录,你能不能管理她家的森林,并且回答她的询问呢?

题解

这题太神了,废了我一下午。

看到区间操作,就可以想到差分或者扫描线,我们会发现这题基本没有好的方法去执行批量操作,所以我们要用扫描线。

这道题的操作有,区间生长一个点,区间换父亲。

我们对于每个1操作新建一个虚点,然后把它们串起来,然后把每个0操作长出来的点挂在上一个虚点上,然后一通做完之后的树长这样(白点为虚点,黑点为实点)。

时间从上到下为从早到晚。

对于一个换父亲操作,假如说我们要对最下面的白点对应的换父亲的操作换到右边从上到下第二个黑点上,那么我们可以这样。

可以手玩一下,所有有效节点对应的deep是对的。

然后我们用LCT维护这一过程,求两点

注意判断1操作的作用范围。

代码

#include<iostream>
#include<cstdio>
#include<algorithm>
#define N 200002
using namespace std;
int tr[N][2],fa[N],size[N],w[N],cnt,n,m,tot,top,b[N],L[N],R[N],ji[N],qqq,ans,ans2[N];
inline int rd(){
    int x=0;char c=getchar();bool f=0;
    while(!isdigit(c)){if(c=='-')f=1;c=getchar();}
    while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=getchar();}
    return f?-x:x;
}
inline bool isroot(int x){return !x||(tr[fa[x]][0]!=x&&tr[fa[x]][1]!=x);}
inline bool ge(int x){return tr[fa[x]][1]==x;}
inline void pushup(int x){size[x]=size[tr[x][0]]+size[tr[x][1]]+w[x];}
inline void newnode(int x){++cnt;w[cnt]=size[cnt]=x;}
inline void rotate(int x){
    int y=fa[x],o=ge(x);
    if(isroot(x))return;
    tr[y][o]=tr[x][o^1];fa[tr[y][o]]=y;
    if(!isroot(y))tr[fa[y]][ge(y)]=x;fa[x]=fa[y];
    fa[y]=x;tr[x][o^1]=y;
    pushup(y);pushup(x);
}
inline void splay(int x){
    while(!isroot(x)){ 
        int y=fa[x];
        if(isroot(y))rotate(x);
        else rotate(ge(y)==ge(x)?y:x),rotate(x);
    }
}
inline int access(int x){int y=0;for(;x;y=x,x=fa[x])splay(x),tr[x][1]=y,pushup(x);return y;}//qiu LCA get
inline void link(int x,int y){access(x);splay(x);fa[x]=y;}
inline void cut(int x){access(x);splay(x);fa[tr[x][0]]=0;tr[x][0]=0;pushup(x);}
struct node{
    int pos,tag,x,y;
    inline bool operator <(const node &b)const{
        if(pos!=b.pos)return pos<b.pos;
        else return tag<b.tag;
    } 
}a[N<<1];
int main(){
    n=rd();m=rd();int opt,l,r,k;
    newnode(1);newnode(0);link(2,1);
    int now=2;b[tot=1]=1;L[tot]=1;R[tot]=n;
    for(int i=1;i<=m;++i){
        opt=rd();
        if(!opt){
             l=rd();r=rd();newnode(1);
             b[++tot]=cnt;L[tot]=l;R[tot]=r;
             a[++top]=node{1,i-N,cnt,now};
        }
        else if(opt==1){
            l=rd();r=rd();k=rd();l=max(l,L[k]);r=min(r,R[k]);
            if(l>r)continue;
            newnode(0);link(cnt,now);
            a[++top]=node{l,i-N,cnt,b[k]};a[++top]=node{r+1,i-N,cnt,now};
            now=cnt;
        }
        else{
            k=rd();l=rd();r=rd();ji[i]=++qqq;
            a[++top]=node{k,i,b[l],b[r]};
        }
    } 
    sort(a+1,a+top+1);int p=1;
    for(int i=1;i<=n;++i)
      for(;a[p].pos==i;++p)
          if(a[p].tag<=0){cut(a[p].x);link(a[p].x,a[p].y);}
          else{
              ans=0;
              access(a[p].x);splay(a[p].x);ans+=size[a[p].x];
              int lca=access(a[p].y);splay(a[p].y);ans+=size[a[p].y];
              access(lca);splay(lca);ans-=size[lca]*2;
              ans2[ji[a[p].tag]]=ans;
        }
    for(int i=1;i<=qqq;++i)printf("%d\n",ans2[i]);
    return 0;
}

 

posted @ 2018-12-27 20:05  comld  阅读(174)  评论(0编辑  收藏  举报