動態樹問題 ,是一類要求維護一個有根樹森林,支持對樹的分割, 合併等操作的問題。由RobertE.Tarjan為首的科學家們提出解決算法Link-Cut Trees,簡稱lct。
基本介紹
- 中文名:動態樹問題
- 外文名:Dynamic Trees Problem
- 別名:LCT
- 算法:Link-Cut Trees,splay
- 創始人:Sleator 和Tarjan
- 時間複雜度:O((n + q) log n)
定義
問題描述
- 查詢一個點的地糊抹父親
- 查詢一個點所在的樹的根
- 修改某個節點的權察院
- 向從某個節點到它所在的樹的根的路徑上的所有的節跨簽肯點的權增加一個數
- 查詢從某個節點到它所在的樹的根的路徑上的所有的節點的權的最小值
- 把一棵樹從某個節點和它的父親處斷開,使其成為兩棵樹
- 讓一棵樹的根成為另一棵樹的某個節點的兒子,從而合併這兩棵樹
- 把某棵樹的根修改為它的某個節點
- 查詢在同一棵樹上的兩個節點的LCA
- 修改以某個節點為根的子樹的所有節點的權
- 查詢以某個節點為根的子樹的所有節點的權的最小值
出現
解法
void link(node *f,node *x,bool d)
{
f->s[d]=x;
if(x) x->p=f;
update(f);
}
bool is_root(node *now){return !now->p||now!=now->p->s[0]&&now!=now->p->s[1];}
void rotate(node *now,bool d)
{
node *x=now->s[d],*p=now->p;
bool flag=is_root(now);
link(now,x->s[d^1],d);
link(x,now,d^1);
if(flag) x->p=p;
else link(p,x,now==p->s[1]);
}
stack<node*>s;
void splay(node *now)
{
s.push(now);
for(node *i=now;!is_root(i);i=i->p) s.push(i->p);
while(!s.empty()) down(s.top()),s.pop();
while(!is_root(now))
{
node *cur=now->p;
bool d1=now==cur->s[1];
if(is_root(cur))
{
rotate(cur,d1);
return;
}
node *x=cur->p;
bool d2=cur==x->s[1];
if(d1^d2) rotate(cur,d1),rotate(x,d2);
else rotate(x,d2),rotate(cur,d1);
}
}
void link(node *f,node *x,bool d)
{
f->s[d]=x;
if(x) x->p=f;
update(f);
}
bool is_root(node *now){return !now->p||now!=now->p->s[0]&&now!=now->p->s[1];}
void rotate(node *now,bool d)
{
node *x=now->s[d],*p=now->p;
bool flag=is_root(now);
link(now,x->s[d^1],d);
link(x,now,d^1);
if(flag) x->p=p;
else link(p,x,now==p->s[1]);
}
實例套用
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int MAXN=1e5+10;
struct node{
int v,upv,downv,sum,lz;
bool lz_rev;
node *p,*s[2];
void build(int x)
{
v=upv=downv=x;
sum=1;
lz=0;
lz_rev=0;
p=s[0]=s[1]=NULL;
}
}*root[MAXN];
void update(node *now)
{
if(!now) return;
now->upv=now->s[0]?now->s[0]->upv:now->v;
now->downv=now->s[1]?now->s[1]->downv:now->v;
now->sum=1;
if(now->s[0]) now->sum+=now->s[0]->sum-(now->v==now->s[0]->downv);
if(now->s[1]) now->sum+=now->s[1]->sum-(now->v==now->s[1]->upv);
}
void print(node *now,int x)
{
if(!now) return;
now->v=now->upv=now->downv=x;
now->sum=1;
now->lz=x;
}
void rev(node *now)
{
if(now)
{
swap(now->s[0],now->s[1]);
swap(now->upv,now->downv);
now->lz_rev^=1;
}
}
void down(node *now)
{
if(now->lz_rev)
{
rev(now->s[0]);
rev(now->s[1]);
now->lz_rev=0;
}
if(now->lz)
{
print(now->s[0],now->lz);
print(now->s[1],now->lz);
now->lz=0;
}
update(now);
}
void link(node *f,node *x,bool d)
{
f->s[d]=x;
if(x) x->p=f;
update(f);
}
bool is_root(node *now){return !now->p||now!=now->p->s[0]&&now!=now->p->s[1];}
void rotate(node *now,bool d)
{
node *x=now->s[d],*p=now->p;
bool flag=is_root(now);
link(now,x->s[d^1],d);
link(x,now,d^1);
if(flag) x->p=p;
else link(p,x,now==p->s[1]);
}
stack<node*>s;
void splay(node *now)
{
s.push(now);
for(node *i=now;!is_root(i);i=i->p) s.push(i->p);
while(!s.empty()) down(s.top()),s.pop();
while(!is_root(now))
{
node *cur=now->p;
bool d1=now==cur->s[1];
if(is_root(cur))
{
rotate(cur,d1);
return;
}
node *x=cur->p;
bool d2=cur==x->s[1];
if(d1^d2) rotate(cur,d1),rotate(x,d2);
else rotate(x,d2),rotate(cur,d1);
}
}
void access(node *now)
{
node *x=NULL,*st=now;
while(now)
{
splay(now);
link(now,x,1);
x=now;
now=now->p;
}
splay(st);
}
void set_root(node *now){access(now),rev(now);}
void extract(node *x,node *y){set_root(x),access(y);}
void con(node *x,node *y){set_root(x),x->p=y;}
int n,m;
int main()
{
ios::sync_with_stdio(0);
cin>>n>>m;
for(int i=1;i<=n;++i)
{
int a;
cin>>a;
root[i]=new node;
root[i]->build(a);
}
for(int i=1;i<n;++i)
{
int a,b;
cin>>a>>b;
con(root[a],root[b]);
}
while(m--)
{
char op;
int x,y,z;
cin>>op;
if(op=='C')
{
cin>>x>>y>>z;
extract(root[x],root[y]);
print(root[y],z);
}
else
{
cin>>x>>y;
extract(root[x],root[y]);
cout<<root[y]->sum<<endl;
}
}
return 0;
}
void link(node *f,node *x,bool d)
{
f->s[d]=x;
if(x) x->p=f;
update(f);
}
bool is_root(node *now){return !now->p||now!=now->p->s[0]&&now!=now->p->s[1];}
void rotate(node *now,bool d)
{
node *x=now->s[d],*p=now->p;
bool flag=is_root(now);
link(now,x->s[d^1],d);
link(x,now,d^1);
if(flag) x->p=p;
else link(p,x,now==p->s[1]);
}
實例套用
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int MAXN=1e5+10;
struct node{
int v,upv,downv,sum,lz;
bool lz_rev;
node *p,*s[2];
void build(int x)
{
v=upv=downv=x;
sum=1;
lz=0;
lz_rev=0;
p=s[0]=s[1]=NULL;
}
}*root[MAXN];
void update(node *now)
{
if(!now) return;
now->upv=now->s[0]?now->s[0]->upv:now->v;
now->downv=now->s[1]?now->s[1]->downv:now->v;
now->sum=1;
if(now->s[0]) now->sum+=now->s[0]->sum-(now->v==now->s[0]->downv);
if(now->s[1]) now->sum+=now->s[1]->sum-(now->v==now->s[1]->upv);
}
void print(node *now,int x)
{
if(!now) return;
now->v=now->upv=now->downv=x;
now->sum=1;
now->lz=x;
}
void rev(node *now)
{
if(now)
{
swap(now->s[0],now->s[1]);
swap(now->upv,now->downv);
now->lz_rev^=1;
}
}
void down(node *now)
{
if(now->lz_rev)
{
rev(now->s[0]);
rev(now->s[1]);
now->lz_rev=0;
}
if(now->lz)
{
print(now->s[0],now->lz);
print(now->s[1],now->lz);
now->lz=0;
}
update(now);
}
void link(node *f,node *x,bool d)
{
f->s[d]=x;
if(x) x->p=f;
update(f);
}
bool is_root(node *now){return !now->p||now!=now->p->s[0]&&now!=now->p->s[1];}
void rotate(node *now,bool d)
{
node *x=now->s[d],*p=now->p;
bool flag=is_root(now);
link(now,x->s[d^1],d);
link(x,now,d^1);
if(flag) x->p=p;
else link(p,x,now==p->s[1]);
}
stack<node*>s;
void splay(node *now)
{
s.push(now);
for(node *i=now;!is_root(i);i=i->p) s.push(i->p);
while(!s.empty()) down(s.top()),s.pop();
while(!is_root(now))
{
node *cur=now->p;
bool d1=now==cur->s[1];
if(is_root(cur))
{
rotate(cur,d1);
return;
}
node *x=cur->p;
bool d2=cur==x->s[1];
if(d1^d2) rotate(cur,d1),rotate(x,d2);
else rotate(x,d2),rotate(cur,d1);
}
}
void access(node *now)
{
node *x=NULL,*st=now;
while(now)
{
splay(now);
link(now,x,1);
x=now;
now=now->p;
}
splay(st);
}
void set_root(node *now){access(now),rev(now);}
void extract(node *x,node *y){set_root(x),access(y);}
void con(node *x,node *y){set_root(x),x->p=y;}
int n,m;
int main()
{
ios::sync_with_stdio(0);
cin>>n>>m;
for(int i=1;i<=n;++i)
{
int a;
cin>>a;
root[i]=new node;
root[i]->build(a);
}
for(int i=1;i<n;++i)
{
int a,b;
cin>>a>>b;
con(root[a],root[b]);
}
while(m--)
{
char op;
int x,y,z;
cin>>op;
if(op=='C')
{
cin>>x>>y>>z;
extract(root[x],root[y]);
print(root[y],z);
}
else
{
cin>>x>>y;
extract(root[x],root[y]);
cout<<root[y]->sum<<endl;
}
}
return 0;
}