zoukankan      html  css  js  c++  java
  • $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());
        }
    }
    
  • 相关阅读:
    数组
    字符对象的方法
    事件
    判断数据类型
    数据类型和变量
    语法
    快速入门
    JavaScript简介
    Spring init-method和destroy-method属性的使用
    spring3后提供了的context:property-placeholder/元素
  • 原文地址:https://www.cnblogs.com/ZUTTER/p/10853430.html
Copyright © 2011-2022 走看看