[UOJ195]大森林(LCT建虚点)

#195. 【ZJOI2016】大森林

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

小Y掌握了一种魔法,能让第 l l 棵树到第 r r 棵树的生长节点长出一个子节点。同时她还能修改第 l l 棵树到第 r r 棵树的生长节点。

她告诉了你她使用魔法的记录,你能不能管理她家的森林,并且回答她的询问呢?

输入格式

第一行包含 2 个正整数 n,m n , m ,共有 n n 棵树和 m m 个操作。

接下来 m m 行,每行包含若干非负整数表示一个操作,操作格式为:

  1. 0 0 l l r r 表示将第 l l 棵树到第 r r 棵树的生长节点下面长出一个子节点,子节点的标号为上一个 0 0 号操作叶子标号加 1 1 (例如,第一个 0 0 号操作产生的子节点标号为 2 2 ), l l r r 之间的树长出的节点标号都相同。保证 1lrn 1 ≤ l ≤ r ≤ n
  2. 1 1 l l r r x x 表示将第 l l 棵树到第 r r 棵树的生长节点改到标号为 x x 的节点。对于区间内的每棵树,如果标号 x x 的点不在其中,那么这个操作对该树不产生影响。保证 1lrn 1 ≤ l ≤ r ≤ n x x 不超过当前所有树中节点最大的标号。
  3. 2 2 x x u u v v 询问第 x x 棵树中节点 u u 到节点 v v 的距离,也就是在第 x x 棵树中从节点 u u 和节点 v v 的最短路上边的数量。保证 1xn 1 ≤ x ≤ n ,这棵树中节点 u u 和节点 v v 存在。

输出格式

输出包括若干行,按顺序对于每个小Y的询问输出答案。

样例一

input

5 5
0 1 5
1 2 4 2
0 1 4
2 1 1 3
2 2 1 3

output

1
2

样例二

见样例数据下载。

限制与约定

测试点编号 n n m m 约定
1 103 ≤ 10 3 103 ≤ 10 3
2 105 ≤ 10 5 2×105 ≤ 2 × 10 5 保证每次 0 0 1 1 操作修改的是 1 1 n n 所有的树
3
4 保证每次 0 0 操作生长节点都是这些树中编号最大的节点
5
6
7
8
9
10

时间限制: 2s 2 s

空间限制: 256MB 256 MB


思路&&分析:

    对于每一个1操作,我们可以建一个虚点,然后对于每个0操作都将这些点挂在[在这个操作前面最迟的1操作上建的虚点]的下面。于是我们可以将操作离线,然后从左到右把所有树都扫一遍就行了,这样一来我们打一颗LCT就完事了。

Code

#pragma GCC optimize(3)
#include
using namespace std;
typedef long long ll;
bool Finish_read;
template<class T>inline void read(T &x){Finish_read=0;x=0;int f=1;char ch=getchar();while(!isdigit(ch)){if(ch=='-')f=-1;if(ch==EOF)return;ch=getchar();}while(isdigit(ch))x=x*10+ch-'0',ch=getchar();x*=f;Finish_read=1;}
template<class T>inline void print(T x){if(x/10!=0)print(x/10);putchar(x%10+'0');}
template<class T>inline void writeln(T x){if(x<0)putchar('-');x=abs(x);print(x);putchar('\n');}
template<class T>inline void write(T x){if(x<0)putchar('-');x=abs(x);print(x);}
/*================Header Template==============*/
const int maxn=200005;
int c[maxn][2],sz[maxn],val[maxn],fa[maxn],p,cnt,m,n,tot,le[maxn],ri[maxn],id[maxn],now,ans[maxn];
struct Event {
    int pos,op,x,y;
    Event(){}
    Event(const int &pos,const int &op,const int &x,const int &y):pos(pos),op(op),x(x),y(y){}
    inline bool operator < (const Event &rhs) const {
        return pos==rhs.pos?op2];
inline void pushup(int x) {
    int l=c[x][0],r=c[x][1];
    sz[x]=sz[l]+sz[r]+val[x];
}
inline bool isrt(int x) {
    return c[fa[x]][0]!=x&&c[fa[x]][1]!=x;
}
inline void rotate(int x) {
    int y=fa[x],z=fa[y],l=(c[y][1]==x),r=l^1;
    if(!isrt(y))
        c[z][c[z][1]==y]=x;
    fa[y]=x,fa[x]=z;
    fa[c[x][r]]=y;
    c[y][l]=c[x][r];
    c[x][r]=y;
    pushup(y),pushup(x);
}
inline void splay(int x) {
    while(!isrt(x)) {
        int y=fa[x],z=fa[y];
        if(!isrt(y)) {
            if(c[y][0]==x^c[z][0]==y)
                rotate(x);
            else
                rotate(y);
        }
        rotate(x);
    }
}
inline int access(int x) {
    int t=0;
    for(;x;t=x,x=fa[x])
        splay(x),c[x][1]=t,pushup(x);
    return t;
}
inline void cut(int x) {
    access(x);
    splay(x);
    c[x][0]=fa[c[x][0]]=0;
    pushup(x);
}
inline void link(int x,int y) {
    splay(x);
    fa[x]=y;
}
inline void add(int o) {
    sz[n+1]=val[++n]=o;
}
int main() {
    read(p),read(m);
    add(1),cnt=1,le[cnt]=id[cnt]=1,ri[cnt]=p,add(0),now=2,link(2,1);
    memset(ans,-1,sizeof ans);
    for(int i=1,op,k,x,y;i<=m;i++) {
        read(op);
        if(op==0) {
            read(x);read(y);++cnt;
            le[cnt]=x,ri[cnt]=y,add(1),id[cnt]=n;
            a[++tot]=Event(1,i-m,n,now);
        }
        else if(op==1) {
            read(x),read(y),read(k);
            x=max(x,le[k]),y=min(y,ri[k]);
            if(x<=y) {
                add(0);
                if(x>1)
                    link(n,now);
                a[++tot]=Event(x,i-m,n,id[k]);
                a[++tot]=Event(y+1,i-m,n,now); 
                now=n;
            }
        }
        else {
            read(k),read(x),read(y);
            a[++tot]=Event(k,i,id[x],id[y]);
        }
    }
    sort(a+1,a+tot+1);
    for(int i=1,k=1;i<=p;i++)
        for(;k<=tot&&a[k].pos==i;k++)
            if(a[k].op>0) {
                access(a[k].x),splay(a[k].x),ans[a[k].op]=sz[a[k].x];
                int t=access(a[k].y);splay(a[k].y),ans[a[k].op]+=sz[a[k].y];
                access(t),splay(t),ans[a[k].op]-=sz[t]<<1;
            }
            else {
                cut(a[k].x);
                link(a[k].x,a[k].y);
            }
    for(int i=1;i<=m;i++)
        if(ans[i]!=-1)
            printf("%d\n",ans[i]);
    return 0;
}

你可能感兴趣的:(LCT)