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());
}
}