【模板篇】Link Cut Tree模板(指针)

网上一片一片的LCT都是数组写的 orz
用指针写splay的人想用指针写LCT找板子都不好找QAQ
所以能A题了之后自然要来回报社会, 把自己的板子丢上来(然而根本没有人会看)

LCT讲解就省省吧, 我这种蒟蒻也基本讲不清楚, 就扔个板子算了
板子里也没什么注释, 因为函数的命名和世界的主流命名规范是一样的..

那就这样吧.. 贴两道题的板子.
第一个是SDOI2008 Cave洞穴勘测, 一道简单判断连通性的LCT裸题.
三种操作;

  1. 连x,y 保证连完还是棵树
  2. 断x,y 保证<x,y>边存在
  3. 询问x,y是否联通
    然而据说用不路径压缩的并查集可过(考场上我估计就写这个了

代码:

#include <cstdio>
#include <algorithm>
using namespace std;
const int N=20101;
inline int gn(int a=0,char c=0){
    for(;c<'0'||c>'9';c=getchar());
    for(;c>47&&c<58;c=getchar())a=a*10+c-48;return a;
}
struct node{
    node *fa,*ch[2];
    bool rev;
    bool getwh();
    bool isroot();
    void pushdown();
    void setch(bool wh,node* child);
}pool[N],*null; int tot;
bool node::getwh(){
    return fa->ch[1]==this;
}
bool node::isroot(){
    return fa==null||(fa->ch[0]!=this&&fa->ch[1]!=this);
}
void node::pushdown(){
    if(null==this||!rev) return;
    swap(ch[0],ch[1]);
    ch[0]->rev^=1; ch[1]->rev^=1;
    rev=0;
}
void node::setch(bool wh,node* child){
    pushdown(); ch[wh]=child;
    if(null!=child) child->fa=this;
}
void init(){
    null=pool; null->rev=0;
    null->fa=null->ch[0]=null->ch[1]=null;
}
node* newnode(){
    node* x=pool+ ++tot; x->rev=0;
    x->ch[0]=x->ch[1]=x->fa=null;
    return x;
}
void rotat(node* x){
    node *fa=x->fa,*fafa=fa->fa;
    if(fafa!=null) fafa->pushdown();
    fa->pushdown(); x->pushdown();
    int wh=x->getwh();
    if(fa->isroot()) x->fa=fa->fa;
    else fafa->setch(fa->getwh(),x);
    fa->setch(wh,x->ch[wh^1]);
    x->setch(wh^1,fa);
}
void fix(node* x){
    if(!x->isroot()) fix(x->fa);
    x->pushdown();
}
void splay(node* x){
    fix(x);
    for(;!x->isroot();rotat(x))
        if(!x->fa->isroot())
            x->getwh()==x->fa->getwh()?rotat(x->fa):rotat(x);
}
node* access(node* x){
    node* y=null;
    for(;x!=null;x=x->fa){
        splay(x); x->ch[1]=y; y=x;
    }
    return y;
}
void makeroot(node* x){
    access(x)->rev^=1;
    splay(x);
}
void link(node* x,node* y){
    makeroot(x); x->fa=y;
}
void cut(node* x,node* y){
    makeroot(x); access(y); splay(y);
    x->fa=y->ch[0]=null;
}
node* Find(node* x){
    for(access(x),splay(x);x->ch[0]!=null;x->pushdown(),x=x->ch[0]);
    return x;
}
int main(){ init();
    int n=gn(),m=gn();
    for(int i=1;i<=n;++i) newnode();
    char opt[123];
    for(int i=1;i<=m;++i){
        scanf("%s",opt);
        int x=gn(),y=gn();
        node *X=pool+x,*Y=pool+y;
        if(opt[0]=='Q')
            puts(Find(X)==Find(Y)?"Yes":"No");
        else if(opt[0]=='C')
            link(X,Y);
        else cut(X,Y);
    }   
}

然后另一道是luogu的模板题, 这个是带点权的
(如果带边权的话还是化边为点...)
四种操作:

  1. 查询x,y路径的异或和
  2. 连x,y 已连通则忽略
  3. 断x,y 不保证x,y间有边
  4. 单点修改

代码:

#include <cstdio>
#include <algorithm>
using namespace std;
const int N=300020;
inline int gn(int a=0,char c=0){
    for(;c<'0'||c>'9';c=getchar());
    for(;c>47&&c<58;c=getchar())a=a*10+c-48;return a;
}
struct node{
    node *fa,*ch[2];
    bool rev; int xum,xx;
    bool getwh(){return fa->ch[1]==this;}
    bool isroot();
    void update(){
        xum=ch[0]->xum^ch[1]->xum^xx;
    }
    void pushdown();
    void setch(bool wh,node* child);
}pool[N],*null;
int tot;
bool node::isroot(){
    return fa==null||(fa->ch[0]!=this&&fa->ch[1]!=this);
}
void node::pushdown(){
    if(this==null||!rev) return;
    swap(ch[0],ch[1]);
    ch[0]->rev^=1;
    ch[1]->rev^=1;
    rev=0;
}
void node::setch(bool wh,node* child){
    pushdown(); ch[wh]=child;
    if(child!=null) child->fa=this;
}
void init(){
    null=pool; null->ch[0]=null->ch[1]=null->fa=null; null->rev=0;
}
node* newnode(int val){
    node* x=pool+ ++tot; x->xx=val;
    x->ch[0]=x->ch[1]=x->fa=null;
    x->rev=0; return x;
}
void rotat(node* x){
    node *fa=x->fa,*fafa=fa->fa;
    if(!fa->isroot()) fafa->pushdown();
    fa->pushdown(); x->pushdown();
    int wh=x->getwh();
    fa->setch(wh,x->ch[wh^1]);
    if(fa->isroot()) x->fa=fa->fa;
    else fafa->setch(fa->getwh(),x);
    x->setch(wh^1,fa);
    fa->update(); x->update();
}
void fix(node* x){
    if(!x->isroot()) fix(x->fa);
    x->pushdown();
}
void splay(node *x){
    fix(x);
    for(;!x->isroot();rotat(x))
        if(!x->fa->isroot())
            x->getwh()==x->fa->getwh()?rotat(x->fa):rotat(x);
    x->update();
}
node* access(node* x){
    node* y=null;
    for(;x!=null;x=x->fa){
        splay(x);
        x->ch[1]=y;
        x->update(); 
        y=x;
    }
    return y;
}
void makeroot(node* x){
    access(x)->rev=1; splay(x);
}
void link(node* x,node* y){
    makeroot(x);
    x->fa=y;
//  access(x);
}
void cut(node* x,node* y){
    makeroot(x); access(y); splay(y);
    x->fa=y->ch[0]=null;
}
node* Find(node* x){
    for(access(x),splay(x);x->ch[0]!=null;x->pushdown(),x=x->ch[0]);
    return x;
}
void change(node* x,int y){
    access(x); splay(x);
    x->xx=y; x->update();
}
int query(node* x,node* y){
    makeroot(x);
    access(y);
    splay(y);
    return y->xum;
}
int main(){
    init();
    int n=gn(),m=gn();
    for(int i=1;i<=n;++i) newnode(gn());
    for(int i=1;i<=m;++i){
        int opt=gn(),x=gn(),y=gn();
        node *X=pool+x,*Y=opt==3?null:pool+y;
        switch(opt){
            case 0:
                printf("%d\n",query(X,Y));
                break;
            case 1:
                if(Find(X)!=Find(Y))
                    link(X,Y);
                break;
            case 2:
                if(Find(X)==Find(Y))
                    cut(X,Y);
                break;
            case 3:
                change(X,y);
                break;
        }
    }
}

就这样吧...

转载于:https://www.cnblogs.com/enzymii/p/8512335.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值