————學習LCT的同學建議去研究楊哲大神的《QTREE解法的一些研究》,自覺講得十分詳細。
LCT的核心算法也就是幾個過程:access.makeroot,link,cut……
搞出這幾個過程LCT也不是啥難寫的東西啦。
在最近做了幾道入門題,奉上。
spoj qtree3
樹上支持修改顏色(黑白),查詢路徑上第一個黑點編號。
直接LCT搞吧,記錄路徑上黑點的數量。修改時把x店轉到更直接改,查詢時在樹上走直到第一個黑點即可。
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int Maxn=100005;
#define isroot(x) ((son[fa[x]][0]!=x) && (son[fa[x]][1]!=x))
#define update(x) sum[x]=sum[son[x][0]]+sum[son[x][1]]+flag[x]
int fa[Maxn],son[Maxn][2],rev[Maxn],sum[Maxn],flag[Maxn];
int n,q,i,K,x,y;
void push(int x){
swap(son[x][0],son[x][1]);
if (son[x][0]>0)
rev[son[x][0]]^=1;
if (son[x][1]>0)
rev[son[x][1]]^=1;
rev[x]=0;
}
void rotate(int x,int f,int K){
if (!isroot(f)){
if (son[fa[f]][0]==f) son[fa[f]][0]=x;
else son[fa[f]][1]=x;
}
fa[x]=fa[f];
if (son[x][K^1]>0)
fa[ son[x][K^1] ]=f;
son[f][K]=son[x][K^1];
son[x][K^1]=f; fa[f]=x;
update(f);
}
void Splay(int x){
int f, gf;
while (!isroot(x)){
f=fa[x]; gf=fa[f];
if (rev[gf]) push(gf);
if (rev[f]) push(f);
if (rev[x]) push(x);
if (isroot(f)){
if (son[f][0]==x) rotate(x,f,0);
if (son[f][1]==x) rotate(x,f,1);
} else
{
if (son[f][0]==x && son[gf][0]==f) rotate(f,gf,0), rotate(x,f,0);
if (son[f][1]==x && son[gf][1]==f) rotate(f,gf,1), rotate(x,f,1);
if (son[f][0]==x && son[gf][1]==f) rotate(x,f,0), rotate(x,gf,1);
if (son[f][1]==x && son[gf][0]==f) rotate(x,f,1), rotate(x,gf,0);
}
}
if (rev[x]) push(x);
update(x);
}
void access(int x){
int t=0;
while (x){
Splay(x);
son[x][1]=t;
update(x);
t=x; x=fa[x];
}
}
void makeroot(int x)
{ access(x); Splay(x); rev[x]^=1; }
void Link(int x,int y)
{ makeroot(x); fa[x]=y; access(x);}
void cut(int x,int y){
makeroot(x); access(y); Splay(y);
fa[son[y][0]]=0; son[y][0]=0;
Splay(x); Splay(y);
}
int main(){
freopen("qtree3.in","r",stdin);
freopen("qtree3.out","w",stdout);
scanf("%d%d",&n,&q);
for (i=1;i<n;i++){
scanf("%d%d",&x,&y);
Link(x,y);
}
for (i=1;i<=q;i++){
scanf("%d%d",&K,&x);
if (K==0){
makeroot(x);
flag[x]^=1;
update(x);
} else
{
makeroot(1);
access(x);
Splay(x);
if (sum[x]==0) {puts("-1");continue;}
while (sum[x]>0){
if (rev[x]) push(x);
if (sum[son[x][0]]>0) x=son[x][0];
else if (flag[x]==1) break;
else x=son[x][1];
}
printf("%d\n",x);
}
}
return 0;
}
spoj gss7
樹上支持修改整個路徑上的值,詢問路徑上最大子序列和。
LCT+標記大法!像gss1一樣維護最大子序列和,把它套到LCT裏就好了
//注意標記的傳遞順序。
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int Maxn=100005;
#define isroot(x) ((son[fa[x]][0]!=x)&&(son[fa[x]][1]!=x))
int son[Maxn][2],fa[Maxn],rev[Maxn],size[Maxn],sum[Maxn];
int tip[Maxn],lef[Maxn],rig[Maxn],maxx[Maxn],w[Maxn];
int n,m,i,x,y,z,K;
void push1(int x){
swap(son[x][0],son[x][1]);
//swap(lef[x],rig[x]);
if (son[x][0]>0){
rev[son[x][0]]^=1;
swap(lef[son[x][0]],rig[son[x][0]]);
}
if (son[x][1]>0){
rev[son[x][1]]^=1;
swap(lef[son[x][1]],rig[son[x][1]]);
}
rev[x]=0;
}
void push2(int x){
int y;
if (son[x][0]>0){
y=son[x][0];
w[y]=tip[y]=tip[x];
sum[y]=w[y]*size[y];
if (tip[y]<0) maxx[y]=lef[y]=rig[y]=0;
else maxx[y]=lef[y]=rig[y]=tip[y]*size[y];
}
if (son[x][1]>0){
y=son[x][1];
w[y]=tip[y]=tip[x];
sum[y]=w[y]*size[y];
if (tip[y]<0) maxx[y]=lef[y]=rig[y]=0;
else maxx[y]=lef[y]=rig[y]=tip[y]*size[y];
}
tip[x]=-10001;
}
void update(int x){
size[x]=size[son[x][0]]+size[son[x][1]]+1;
sum[x]=sum[son[x][0]]+sum[son[x][1]]+w[x];
lef[x]=max(lef[son[x][0]],sum[son[x][0]]+w[x]+lef[son[x][1]]);
rig[x]=max(rig[son[x][1]],sum[son[x][1]]+w[x]+rig[son[x][0]]);
maxx[x]=max(maxx[son[x][0]],maxx[son[x][1]]);
maxx[x]=max(maxx[x],rig[son[x][0]]+w[x]+lef[son[x][1]]);
}
void rotate(int x,int f,int K){
if (!isroot(f)){
if (son[fa[f]][0]==f) son[fa[f]][0]=x;
else son[fa[f]][1]=x;
}
fa[x]=fa[f];
if (son[x][K^1]>0)
fa[son[x][K^1]]=f;
son[f][K]=son[x][K^1];
fa[f]=x; son[x][K^1]=f;
update(f);
}
void Splay(int x){
int f, gf;
while (!isroot(x)){
f=fa[x]; gf=fa[f];
if (rev[gf]>0) push1(gf);
if (rev[f]>0) push1(f);
if (rev[x]>0) push1(x);
if (tip[gf]>-10001) push2(gf);
if (tip[f]>-10001) push2(f);
if (tip[x]>-10001) push2(x);
if (isroot(f)){
if (son[f][0]==x) rotate(x,f,0);
if (son[f][1]==x) rotate(x,f,1);
} else
{
if (son[f][0]==x && son[gf][0]==f) rotate(f,gf,0), rotate(x,f,0);
if (son[f][1]==x && son[gf][1]==f) rotate(f,gf,1), rotate(x,f,1);
if (son[f][0]==x && son[gf][1]==f) rotate(x,f,0), rotate(x,gf,1);
if (son[f][1]==x && son[gf][0]==f) rotate(x,f,1), rotate(x,gf,0);
}
}
if (rev[x]>0) push1(x);
if (tip[x]>-10001) push2(x);
update(x);
}
void access(int x){
int t=0;
while (x){
Splay(x);
son[x][1]=t;
update(x);
t=x; x=fa[x];
}
}
void makeroot(int x)
{ access(x); Splay(x); rev[x]^=1; swap(lef[x],rig[x]); }
void Link(int x,int y)
{ makeroot(x); fa[x]=y; access(x); }
void cut(int x,int y){
makeroot(x); access(y); Splay(y);
fa[ son[y][0] ]=0; son[y][0]=0;
Splay(x); Splay(y);
}
int main(){
freopen("gss7.in","r",stdin);
freopen("gss7.out","w",stdout);
scanf("%d",&n);
for (i=1;i<=n;i++){
scanf("%d",&w[i]);
size[i]=1;
if (w[i]<0) continue;
sum[i]=lef[i]=rig[i]=maxx[i]=w[i];
}
memset(tip,-10,sizeof(tip));
for (i=1;i<n;i++){
scanf("%d%d",&x,&y);
Link(x, y);
}
scanf("%d",&m);
for (i=1;i<=m;i++){
scanf("%d",&K);
if (K==1){
scanf("%d%d",&x,&y);
makeroot(x);
access(y);
Splay(y);
printf("%d\n",maxx[y]);
} else
{
scanf("%d%d%d",&x,&y,&z);
makeroot(x);
access(y);
Splay(y);
w[y]=tip[y]=z;
sum[y]=z*size[y];
if (z<0) maxx[y]=lef[y]=rig[y]=0;
else maxx[y]=lef[y]=rig[y]=z*size[y];
}
}
return 0;
}
noi2014 day1 T2 魔法森林
//各種騙分ac的算法就不說了。。。。
這題正解是LCT。
將邊按a值從小到大排序,順序掃描加入,維護MST。
爲了方便利用LCT,我們把每條邊看作一個虛點,其權值爲這條邊的b值,他與原圖中的x,y相連,原圖中的點權值就記爲0吧。
每次加入一條邊,如果x,y還未聯通,直接把他們連起來,否則看x,y這條鏈上的最大值是否大於這條邊的權值,去較小的保留。
每加完一條邊求出a+(1~n的最大值),取其中最小值即爲答案。
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
#define isroot(x) ((son[fa[x]][0]!=x)&&(son[fa[x]][1]!=x))
#define update(x) maxx[x]=max(w[x], max(maxx[son[x][0]],maxx[son[x][1]]) )
const int Maxn=200005;
int w[Maxn],rev[Maxn],son[Maxn][2],fa[Maxn];
int maxx[Maxn],F[Maxn],n,m,ans,i,t,m1,m2;
struct EDGE
{
int x,y,a,b;
void read(){ scanf("%d%d%d%d",&x,&y,&a,&b); }
bool operator <(const EDGE &r)const
{ return a<r.a;}
}e[Maxn];
void push(int x){
swap(son[x][0],son[x][1]);
if (son[x][0]>0) rev[son[x][0]]^=1;
if (son[x][1]>0) rev[son[x][1]]^=1;
rev[x]=0;
}
void rotate(int x,int f,int K){
if (!isroot(f)){
if (son[fa[f]][0]==f) son[fa[f]][0]=x;
else son[fa[f]][1]=x;
}
fa[x]=fa[f];
if (son[x][K^1]>0)
fa[ son[x][K^1] ]=f;
son[f][K]=son[x][K^1];
son[x][K^1]=f; fa[f]=x;
update(f);
}
void Splay(int x){
int f, gf;
while (!isroot(x)){
f=fa[x]; gf=fa[f];
if (rev[gf]>0) push(gf);
if (rev[f]>0) push(f);
if (rev[x]>0) push(x);
if (isroot(f)){
if (son[f][0]==x) rotate(x,f,0);
if (son[f][1]==x) rotate(x,f,1);
} else
{
if (son[f][0]==x && son[gf][0]==f) rotate(f,gf,0), rotate(x,f,0);
if (son[f][1]==x && son[gf][1]==f) rotate(f,gf,1), rotate(x,f,1);
if (son[f][0]==x && son[gf][1]==f) rotate(x,f,0), rotate(x,gf,1);
if (son[f][1]==x && son[gf][0]==f) rotate(x,f,1), rotate(x,gf,0);
}
}
if (rev[x]>0) push(x);
update(x);
}
void access(int x){
int t=0;
while (x){
Splay(x);
son[x][1]=t;
update(x);
t=x; x=fa[x];
}
}
void makeroot(int x)
{ access(x); Splay(x); rev[x]^=1; }
void Link(int x,int y)
{ makeroot(x); fa[x]=y; access(x); }
void cut(int x,int y){
makeroot(x); access(y); Splay(y);
fa[ son[y][0] ]=0; son[y][0]=0;
Splay(x); Splay(y);
}
int getit(int x){
int d=maxx[x];
while (true){
if (rev[x]>0) push(x);
if (w[x]==d) break;
if (maxx[son[x][0]]==d) x=son[x][0];
else x=son[x][1];
}
return x-n;
}
int findf(int x){
int xx=x, xxx;
while (xx!=F[xx]) xx=F[xx];
while (x!=xx) xxx=x, x=F[x], F[xxx]=xx;
return xx;
}
int main(){
//freopen("forest.in","r",stdin);
//freopen("forest.out","w",stdout);
scanf("%d%d",&n,&m);
for (i=1;i<=m;i++)
e[i].read();
sort(e+1,e+m+1);
for (i=1;i<=m;i++)
maxx[i+n]=w[i+n]=e[i].b;
ans=(1<<30);
for (i=1;i<=n;i++) F[i]=i;
for (i=1;i<=m;i++){
m1=findf(e[i].x);
m2=findf(e[i].y);
if (m1!=m2){
F[m1]=m2;
Link(e[i].x,i+n);
Link(e[i].y,i+n);
} else{
makeroot(e[i].x);
access(e[i].y);
Splay(e[i].x);
if (maxx[e[i].x]>e[i].b){
t=getit(e[i].x);
cut(e[t].x,t+n);
cut(e[t].y,t+n);
Link(e[i].x,i+n);
Link(e[i].y,i+n);
}
}
m1=findf(1); m2=findf(n);
if (m1==m2){
makeroot(1);
access(n);
Splay(1);
if (ans>e[i].a+maxx[1])
ans=e[i].a+maxx[1];
}
}
if (ans==(1<<30)) ans=-1;
printf("%d\n",ans);
return 0;
}