LCT模板及详细讲解

来源:互联网 发布:淘宝店铺关闭怎么激活 编辑:程序博客网 时间:2024/05/18 02:28

Link cut tree

从一个例子引入:

bzoj1036

此题有两种解法,这里只提LCT的方法。

一棵树上有n个节点,有3个操作:

1、将节点u的权值改为t。

2、询问从点u到点v的路径上的节点的最大权值

3、询问从点u到点v的路径上的节点的权值和

如果学过树链剖分的话此题是可以轻易地解决的,可引入LCT解此题。

LCT换句话说就是多个splay树链来链去,连起来再断开。

其中最基础的操作-----Access,也是最不好理解的。

如果我讲的不能理解的话可以参考杨哲论文《QTREE 解法的一些研究》

Access

如果节点v的子树中,最后被访问的节点在子树w中,则称w为v的Preferred Child,v到w这条边就是Preferred Edge,而由Preferred Edge 连成的路径为Preferred Path,所以,整棵树被划分成了若干条Preferred Path。

如果调用了Access(v),则v的父节点的Preferred Child就变成了v,这样应该可以很好理解Access操作了吧,如果不行可以看论文里的例子。

真实代码和伪代码有点不同。

void access(int x){    for(int t=0;x;t=x,x=fa[x])        splay(x),tr[x][1]=t,update(x);}


接下来介绍其他一些操作:

Makeroot(x):使x所在的splay树中把x作为根节点。

将x的父亲节点的Preferred Child 改为x,然后splay操作将x转到树根,同时rev[x]取反。

void makeroot(int x){    access(x);splay(x);rev[x]^=1;}

Link(x,y):将x节点与y节点连边。

将x节点变为根节点,然后让fa[x]=y;

void link(int x,int y){    makeroot(x);fa[x]=y;}

Split(x,y):将x到y的路径取出(分离)。

void split(int x,int y){    makeroot(x);access(y);splay(y);}


求解u到v的路径上的节点权值和只需split(u,v),然后输出sum[v]即可。


整体代码:


#include <queue>#include <cstdio>#include <iostream>#include <cstring>#include <algorithm>#include <cmath>#define N 30000+30#define ll long longusing namespace std;int read(){    int x=0,f=1;char ch=getchar();    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}    return x*f;}int n,m,top,fa[N],tr[N][2],u[N],v[N],q[N];ll w[N],sum[N],mx[N];bool rev[N];bool isroot(int x){    return tr[fa[x]][0]!=x && tr[fa[x]][1]!=x;}void update(int x){    int l=tr[x][0],r=tr[x][1];    sum[x]=sum[l]+sum[r]+w[x];    mx[x]=max(w[x],max(mx[l],mx[r]));}void pushdown(int x){    int l=tr[x][0],r=tr[x][1];    if(rev[x]){        rev[x]^=1;rev[l]^=1;rev[r]^=1;        swap(tr[x][0],tr[x][1]);    }}inline void rotate(int x){    int f=fa[x],ff=fa[f],l,r;    if(tr[f][0]==x) l=0;else l=1;r=l^1;    if(!isroot(f)) tr[ff][tr[ff][1]==f]=x;    fa[tr[x][r]]=f;fa[f]=x;fa[x]=ff;    tr[f][l]=tr[x][r];tr[x][r]=f;    update(f);update(x);}void splay(int x){    q[++top]=x;    for(int i=x;!isroot(i);i=fa[i]) q[++top]=fa[i];    while(top) pushdown(q[top--]);    while(!isroot(x)){        int f=fa[x],ff=fa[f];        if(!isroot(f)){            if(tr[f][0]==x ^ tr[ff][0]==f) rotate(x);            else rotate(f);        }        rotate(x);    }}void access(int x){    for(int t=0;x;t=x,x=fa[x])        splay(x),tr[x][1]=t,update(x);}void makeroot(int x){    access(x);    splay(x);    rev[x]^=1;}void link(int x,int y){    makeroot(x);fa[x]=y;}void split(int x,int y){    makeroot(x);    access(y);    splay(y);}int main(){    n=read();mx[0]=-(1e9);    for(int i=1;i<n;i++) u[i]=read(),v[i]=read();    for(int i=1;i<=n;i++){        w[i]=read();        sum[i]=mx[i]=w[i];    }    for(int i=1;i<n;i++) link(u[i],v[i]);    m=read();    char ch[10];    int u,v;    while(m--){        scanf("%s",ch);        u=read();v=read();        if(ch[0]=='C'){            splay(u);            w[u]=v;            update(u);        }        if(ch[1]=='M')            split(u,v),printf("%lld\n",mx[v]);        if(ch[1]=='S')            split(u,v),printf("%lld\n",sum[v]);    }    return 0;}
比树链剖分慢qwq

这只是个开始,后面还有很多LCT的变形,这是裸的模板题。

原创粉丝点击