$LCT$

LCT

大概就是用splay维护链来动态维护一棵树

其中splay按照节点深度来排序

那么问题就来了,如果这一条链有的点深度相同怎么办

直接把一端转成根就好了啊

看题


hzoi小B的图

2002: [Hnoi2010]Bounce 弹飞绵羊

显然就是个板子

建原点表示被弹飞了

查询只要查到原点的距离就行了

#include<iostream>
#include<cstring>
#include<cstdio>
#define M 150001
#define ind(x) (c[f[x]][1]==x)
#define ir(x) (c[f[x]][1]==x || c[f[x]][0]==x)
#define flip(x) swap(c[x][0],c[x][1]), r[x]^=1
using namespace std;

int n,m,k,a[M],s[M],c[M][2],f[M],root,r[M],h[M],rt,x,y,fa[M];

inline void update(int x)
{
	s[x]=s[c[x][0]]+s[c[x][1]]+1;
}

inline void pd(int x)
{
	if(!r[x]) return ;
	if(c[x][0]) flip(c[x][0]);
	if(c[x][1]) flip(c[x][1]);
	r[x]=0;
}

inline void con(int x,int y,int z)
{
	if(x) f[x]=y;
	if(y) c[y][z]=x;
}

void rot(int x)
{
	int y=f[x], z=f[y], m1=ind(x), m2=ind(y), C=c[x][!m1];
	if(ir(y)) con(x,z,m2); f[x]=z;
	con(y,x,!m1), con(C,y,m1);
	update(y); update(x);
}

void splay(int x)
{
	int y=x,t=1; h[1]=y;
	while(ir(y)) h[++t]=y=f[y];
	while(t) pd(h[t--]);
	
	while(ir(x))
	{
		if(ir(f[x])) ind(x)==ind(f[x]) ? rot(f[x]) : rot(x);
		rot(x);
	} 
	update(x);
}

void access(int x)
{
	for(int y=0;x;x=f[y=x]) splay(x), c[x][1]=y, update(x);
}

void mr(int x)
{
	access(x); splay(x); flip(x);
}

int fr(int x)
{
	access(x); splay(x); pd(x);
	while(c[x][0]) update(x), x=c[x][0];
	return x;
}

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

void link(int x,int y)
{
	mr(x); if(fr(y)!=x) f[x]=y;
}

void cut(int x,int y)
{
	split(x,y);
	f[x]=c[y][0]=0; update(y);

}

int main()
{
	scanf("%d",&n); rt=n+1;
	s[rt]=1;
	for(int i=1;i<=n;i++)
	{
		scanf("%d",&k);
		if(i+k>n) link(i,rt), fa[i]=rt;
		else link(i,i+k), fa[i]=i+k;
	}
	scanf("%d",&m);
	for(int i=1;i<=m;i++)
	{
		scanf("%d%d",&x,&y); y++;
		if(x==1)
		{ 
			mr(rt); access(y), splay(y);
			printf("%d
",s[y]-1);
		}
		else 
		{
			scanf("%d",&k);
			cut(y,fa[y]); 
			if(y+k>n) link(y,rt), fa[y]=rt;
			else link(y,y+k), fa[y]=y+k;
		}
	}
	return 0;
}


3669: [Noi2014]魔法森林

按照从低到高枚举A,然后用B做动态MST

没啦

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#define M 500001
#define ir(x) ((c[f[x]][0]==x) || (c[f[x]][1]==x)) 
#define ind(x) (c[f[x]][1]==x)
#define flip(x) swap(c[x][0],c[x][1]),r[x]^=1
using namespace std;

int n,m,k,f[M],B[M],s[M],r[M],c[M][2],z[M],h[M],res=0x3f3f3f3f;

struct vv
{
	int fr, ver, a, b;
} g[M];

bool cmp(vv a,vv b) { return (a.a==b.a)?a.b<b.b : a.a<b.a; }

void pd(int x)
{
	if(r[x]) 
	{
		if(c[x][0]) flip(c[x][0]);
		if(c[x][1]) flip(c[x][1]);
		r[x]=0;
	}
}

void update(int x)
{
	B[x]=z[x];
	s[x]=x;
	if(B[c[x][0]]>B[x])
	{
		B[x]=B[c[x][0]];
		s[x]=s[c[x][0]];
	}
	if(B[c[x][1]]>B[x])
	{
		B[x]=B[c[x][1]];
		s[x]=s[c[x][1]];
	}	
}

void rot(int x)
{
	int y=f[x], z=f[y], m1=ind(x), m2=ind(y), C=c[x][!m1];
	if(ir(y)) c[z][m2]=x; c[x][!m1]=y, c[y][m1]=C;
	if(C) f[C]=y; f[x]=z, f[y]=x;
	update(x), update(y);
}

void splay(int x)
{
	int t=1, y=x; h[1]=x;
	while(ir(y)) h[++t]=y=f[y];
	while(t) pd(h[t--]);
	while(ir(x))
	{
		if(ir(f[x])) ind(x)==ind(f[x])?rot(f[x]):rot(x);
		rot(x);
	}
	update(x);
}

void access(int x)
{
	for(int y=0;x;x=f[y=x])
	{
		splay(x); c[x][1]=y; update(x);
	}
}

void mr(int x)
{
	access(x); splay(x); flip(x);
}

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

int fr(int x)
{
	access(x); splay(x);
	while(c[x][0]) pd(x), x=c[x][0];
	return x;
}

void link(int x,int y)
{
	mr(x); if(fr(y)!=x) f[x]=y;
}

void cut(int x,int y)
{
	split(x,y);
	if(fr(y)==x && !c[x][1] && f[x]==y) f[x]=c[y][0]=0, update(y);
}

int main()
{
	scanf("%d%d",&n,&m);
	for(int i=1;i<=m;i++) scanf("%d%d%d%d",&g[i].fr,&g[i].ver,&g[i].a,&g[i].b);
	sort(g+1,g+1+m,cmp);
	for(int i=1;i<=m;i++)
	{
		B[n+i]=z[n+i]=g[i].b; s[n+i]=n+i;
		int x=g[i].fr, y=g[i].ver;
		split(x,y);
		if(fr(y)!=x)
		{
			link(n+i,x);
			link(n+i,y);
			split(1,n);
			if(fr(n)==1) res=min(res,g[i].a+B[n]);
			continue;
		}
		if(B[y]<=B[n+i]) continue;
		int w=s[y];
		cut(w,g[w-n].fr);
		cut(w,g[w-n].ver);  
		link(n+i,x);
		link(n+i,y);
		split(1,n);
		if(fr(n)==1) res=min(res,g[i].a+B[n]);
	}
	if(res==0x3f3f3f3f) printf("%d",-1);
	else printf("%d",res);
}

【模板】动态 DP

由于我永 远 喜 欢 LCT LCT天下第一!

所以我的DDP都是用LCT写的qwq

每个链头维护非重儿子的权值,然后在access的时候改一下就行了

然后这样是一个log的!

跑起来一般是要比树剖快的LCT天下第一!!!

#include<iostream>
#include<cstdio>
#include<algorithm>
#define M 500001
#define inf 0x3f3f3f3fll
using namespace std;

int x,y,n,m,k,a[M],ver[M],nex[M],head[M],cnt,v[M];
int c[M][2],f[M],g[M][2];

int ind(int x)
{
    return (x)==c[f[x]][1];
}

bool ir(int x)
{
    return (((x)==c[f[x]][0]) || ((x)==c[f[x]][1]));
}

struct Mx
{
    int a[2][2];
    void UD(int x,int y)
    {
        a[0][0]=a[0][1]=x, a[1][0]=y, a[1][1]=-inf;
    }
    int Wax() { return max(a[0][0],a[1][0]); }
    Mx operator * (const Mx & A) const
    {
        Mx c;
        for(int i=0;i<2;i++)
            for(int j=0;j<2;j++)
                c.a[i][j]=max(a[i][0]+A.a[0][j],a[i][1]+A.a[1][j]);
        return c;
    }
} d[M];

void add(int x,int y)
{
    ver[++cnt]=y, nex[cnt]=head[x], head[x]=cnt;
    ver[++cnt]=x, nex[cnt]=head[y], head[y]=cnt;
}

void update(int x)
{
    d[x].UD(g[x][0],g[x][1]);
    if(c[x][0]) d[x]=d[c[x][0]]*d[x];
    if(c[x][1]) d[x]=d[x]*d[c[x][1]];
}

void rot(int x)
{
    int y=f[x], z=f[y], m1=ind(x), m2=ind(y), C=c[x][!m1];
    if(ir(y)) c[z][m2]=x; c[x][!m1]=y; c[y][m1]=C;
    if(C) f[C]=y; f[x]=z, f[y]=x;
    update(y), update(x); 
}

void splay(int x)
{
    while(ir(x))
    {
        if(ir(f[x]))  (ind(x)==ind(f[x])) ? rot(f[x]) : rot(x);
        rot(x);
    }
    update(x);
}

void access(int x)
{
    for(int y=0;x;y=x, x=f[x])
    {
        splay(x);
        if(c[x][1])
        {
            g[x][0]+=d[c[x][1]].Wax();
            g[x][1]+=d[c[x][1]].a[0][0];
        }
        if(y)
        {
            g[x][0]-=d[y].Wax();
            g[x][1]-=d[y].a[0][0];
        }
        c[x][1]=y;
        update(x);
    }
}

void dfs(int x,int fa)
{
    g[x][1]=v[x]; f[x]=fa;
    for(int i=head[x];i;i=nex[i])
    {
        if(ver[i]==fa) continue;
        dfs(ver[i],x);
        g[x][0]+=max(g[ver[i]][0],g[ver[i]][1]);
        g[x][1]+=g[ver[i]][0];
    }
    d[x].UD(g[x][0],g[x][1]);
}

int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++) scanf("%d",&v[i]);
    for(int i=1;i<n;i++)
    {
        scanf("%d%d",&x,&y);
        add(x,y);
    }
    dfs(1,0);
    for(int i=1;i<=m;i++)
    {
        scanf("%d%d",&x,&y);
        access(x); 
        splay(x);
        g[x][1]+=y-v[x]; v[x]=y;
        update(x);
        splay(1);
        printf("%d
",d[1].Wax());
    }
}
原文地址:https://www.cnblogs.com/ZUTTER/p/10853430.html