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());
        }
    }
    
  • 相关阅读:
    mac 10.15.7 修改PATH
    oc 属性类型一般用法
    ubuntu解压zip文件名乱码
    telnet 退出
    docker 根据容器创建镜像
    mac android adb device 没有显示设备
    Yii2 查看所有的别名 alias
    Yii2 App Advanced 添加 .gitignore
    ubuntu 18.04 搜狗突然就提示乱码
    An error occured while deploying the file. This probably means that the app contains ARM native code and your Genymotion device cannot run ARM instructions. You should either build your native code to
  • 原文地址:https://www.cnblogs.com/ZUTTER/p/10853430.html
Copyright © 2011-2022 走看看