LCT总结

最近在机房呆的时间蛮多
所以就有时间把以前学的算法复习一下
像lct这种代码量大且不好理解的代码,
一定要及时复习

以前写的模板,多少有些缺陷
所以这次整理了一个优美的

tip

快要考试,我们的目标是:不掉人品,踏实肯干

这里写代码片
#include<cstdio>
#include<cstring>
#include<iostream>

using namespace std;

const int N=1000005;
int n,m,root,cnt;
int size[N],mx[N],pre[N],v[N],ch[N][2],q[N];
bool rev[N];
struct node{
    int x,y,nxt;
};
node way[N<<1];
int st[N],tot=0;

int get(int x)
{
    return ch[pre[x]][0]==x ? 0:1;
    //x是爸爸哪个孩子 
}

int isroot(int x)
{
    return ch[pre[x]][0]!=x&&ch[pre[x]][1]!=x;
    //判断该节点是不是根 
}

void update(int x)  //这里我维护的是子树大小 
{
    size[x]=1;
    if (ch[x][0]) size[x]+=size[ch[x][0]];
    if (ch[x][1]) size[x]+=size[ch[x][1]];
} 

void push(int x)  //一般是用来处理翻转操作的 
{
    if (x&&rev[x])
    {
        rev[x]^=1;
        if (ch[x][0]) rev[ch[x][0]]^=1;
        if (ch[x][1]) rev[ch[x][1]]^=1;
        swap(ch[x][0],ch[x][1]);
    }
} 

void rotate(int x)
{
    int fa=pre[x];
    int grand=pre[fa];
    int wh=get(x);
    if (!isroot(fa)) ch[grand][ch[grand][0]==fa? 0:1]=x;
    //爸爸不是根,那么一定有爷爷 
    ch[fa][wh]=ch[x][wh^1];  //爸爸和儿子的关系一定对应好 
    pre[ch[fa][wh]]=fa;
    pre[x]=grand; pre[fa]=x;
    ch[x][wh^1]=fa;
    update(fa);
    update(x);
}

void splay(int x)
{
    int top=0;
    q[++top]=x;
    for (int i=x;!isroot(i);i=pre[i])   //把该节点到根的所有节点入队 
        q[++top]=pre[i];   //pre[i]
    while (top) push(q[top--]);   //全部push
    for (int fa;!isroot(x);rotate(x))
        if (!isroot(fa=pre[x])) 
            rotate(get(fa)==get(x)? fa:x);
}

void expose(int bh)
{
    int t=0;
    while (bh)
    {
        splay(bh);
        ch[bh][1]=t;   //expose后节点的右儿子就没了 
        update(bh);   //产生了一个新儿子,所以需要update 
        t=bh;
        bh=pre[bh];
    }
}

void makeroot(int bh)
{
    expose(bh);
    splay(bh);
    rev[bh]^=1;   //把x换到根上,那么ta以上的节点深度互换 
}

void link(int x,int y)
{
    makeroot(x);
    pre[x]=y;    //x转到根上之后链接,这样牵扯到的节点较少 
}

void cut(int x,int y)
{
    makeroot(x);
    expose(y);
    splay(y);
    ch[y][0]=pre[x]=0;  
}

int find(int bh)
{
    expose(bh);
    splay(bh);
    while (ch[bh][0]) bh=ch[bh][0];   //找到根节点 
    return bh;
}

int main()
{
    //两点连通性
    if (find(x)==find(y)) printf("Yes\n");
    //两点距离
    makeroot(x);
    expose(y);
    splay(y);
    printf("%d\n",size[ch[y][0]]); 
    //路径上的节点权值和
    makeroot(x);
    expose(y);
    splay(y);
    printf("%d\n",sum[y]);
    //节点到根的距离
    int ro=find(x);
    makeroot(ro);
    expose(x);
    splay(x);
    printf("%d\n",size[ch[x][0]]);
    //更改节点值
    makeroot(x);
    v[x]=z;
    update(x); 
}

转载于:https://www.cnblogs.com/wutongtong3117/p/7673216.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值