ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

洛谷P3348/UOJ#195/LOJ#2092/BZOJ#4573[ZJOI2016]大森林(LCT)

2020-04-21 11:00:50  阅读:169  来源: 互联网

标签:LCT 洛谷 int bl tot ++ 4573 link include


不得不说,ZJOI 的可做题都是数据结构题

 这个东西显然不能在线,所以考虑离线以后从左往右扫过去。同时询问可以把整棵树处理好再处理。

那么我们要处理的就是修改生长结点引发的孩子关系变化。

考虑对每个修改开一个虚点,然后每次生长出的点挂在最近的修改下,相邻修改前后相连,不难发现这种连法像多叉转二叉一样,不会改变实点距离。那么转换就是把对应虚点从它父亲上切下来,连到对应结点上。

这个 LCT 显然不能换根,因此要求 LCA,方法是先 access(u),然后 access(v),那么 v 跳到根碰到的最后一个点就是 LCA。

对于一些树上没有相应结点,判一下就可以了。

#include<cstdio>
#include<vector>
#include<utility>
#define For(i,A,B) for(i=(A);i<=(B);++i)
#define pb push_back
#define mp make_pair
#define fi first
#define se second
using namespace std;
const int N=100050;
const int BUF=1<<22;
char rB[BUF],*rS,*rT,wB[BUF+50],*wT=wB;
inline char gc(){return rS==rT&&(rT=(rS=rB)+fread(rB,1,BUF,stdin),rS==rT)?EOF:*rS++;}
inline void flush(){fwrite(wB,1,wT-wB,stdout);wT=wB;}
inline int rd(){
    char c=gc();
    while(c<48||c>57)c=gc();
    int x=c&15;
    for(c=gc();c>=48&&c<=57;c=gc())x=x*10+(c&15);
    return x;
}
short buf[15];
inline void wt(int x){
    short l=-1;
    if(wT-wB>BUF)flush();
    while(x>9){
        buf[++l]=x%10;
        x/=10;
    }
    *wT++=x|48;
    while(l>=0)*wT++=buf[l--]|48;
    *wT++='\n';
}
int lb[N*2],rb[N*2],bl[N*2],f[N*2],ch[N*2][2],sum[N*2],ans[N*2];
bool val[N*2];
vector<pair<int,int> > L[N],Q[N];
vector<int> R[N],id[N];
inline void chkmin(int &a,int b){if(b<a)a=b;}
inline void chkmax(int &a,int b){if(a<b)a=b;}
inline bool nrt(int o){return ch[f[o]][0]==o||ch[f[o]][1]==o;}
inline bool dir(int o){return ch[f[o]][1]==o;}
inline void pushup(int o){sum[o]=val[o]+sum[ch[o][0]]+sum[ch[o][1]];}
inline void rot(int o){
    int fa=f[o];
    bool d=dir(o);
    f[o]=f[fa];
    if(nrt(fa))ch[f[o]=f[fa]][dir(fa)]=o;
    if(ch[fa][d]=ch[o][d^1])f[ch[fa][d]]=fa;
    f[ch[o][d^1]=fa]=o;
    pushup(fa);
}
inline void splay(int o){
    for(;nrt(o);rot(o))if(nrt(f[o]))rot((dir(o)^(dir(f[o])))?o:f[o]);
    pushup(o);
}
inline int access(int x){
    int y=0;
    for(;x;x=f[y=x]){
        splay(x);
        ch[x][1]=y;
        pushup(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[ch[x][0]]=0;ch[x][0]=0;
//其实这个 cut 是错的,但因为 cut 完立即 link 时进行了 pushup,所以这里可以不用 pushup
}
inline int lca(int x,int y){
    int z,s;
    access(x);splay(x);s=sum[x];
    z=access(y);splay(y);s+=sum[y];
    access(z);splay(z);
    return s-sum[z]*2;
}
int main(){
    int n=rb[1]=rd(),m=rd(),i,j,opt,x,y,z,tot=1,cl=0,ql=0;
    bl[1]=lb[1]=1;
    For(i,1,m){
        opt=rd();x=rd();y=rd();
        if(!opt){
            bl[++tot]=cl;
            lb[tot]=x;rb[tot]=y;
        }else if(opt==1){
            chkmax(x,lb[z=rd()]);chkmin(y,rb[z]);
            if(x>y)continue;
            L[x].pb(mp(++cl,z));
            if(y<n)R[y+1].pb(cl);
        }else{Q[x].pb(mp(y,rd()));id[x].pb(++ql);}
    }
    For(i,1,tot){
        val[i]=1;
        if(i>1)link(i,!bl[i]?1:bl[i]+tot);
    }
    For(i,1,cl)link(i+tot,i>1?i-1+tot:1);
    For(i,1,n){
        For(j,0,(int)R[i].size()-1){
            cut(R[i][j]+tot);
            link(R[i][j]+tot,R[i][j]>1?R[i][j]-1+tot:1);
        }
        For(j,0,(int)L[i].size()-1){
            cut(L[i][j].fi+tot);
            link(L[i][j].fi+tot,L[i][j].se);
        }
        For(j,0,(int)Q[i].size()-1)ans[id[i][j]]=lca(Q[i][j].fi,Q[i][j].se);
    }
    For(i,1,ql)wt(ans[i]);
    flush();
    return 0;
}
View Code

 

标签:LCT,洛谷,int,bl,tot,++,4573,link,include
来源: https://www.cnblogs.com/sunshine-chen/p/12727514.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有