zoukankan      html  css  js  c++  java
  • [BZOJ3159]决战

    XIV.[BZOJ3159]决战

    你们知道吗!把一行 #define int long long 写在了一行 int 的后面然后 debug 了一整天的崩溃你知道吗!!!

    我恨不得罢免了自己!

    言归正传。

    从某种角度来说,这是我写的第一棵树套树!虽然是邪教般的LCT套splay

    首先,除了翻转操作以外的其它操作,都是LCT甚至是树剖的常规操作。关键是这个 翻转 操作。

    或许你会决定这很简单,直接把链 split 出来然后打上翻转的 tag 即可。如果你真这么认为的话,可就错了。LCT中的翻转,是针对的翻转,翻转的时候不仅翻转值,连儿子也一起给你翻了去!我们要实现的,是针对的翻转。LCT维护的是树的形态,我们还需要再开一棵splay维护值域。

    为了方便,我们不如让新的splay一样以深度为键值排序,并维护所有节点的值。为了区别,我们把这棵新splay叫做SPLAY。考虑将同一条链中的所有节点染成同一个颜色(这里的颜色可以是链中任意一个节点的值),并将这一条链中的所有东西打包到一棵SPLAY中。

    我们考虑当LCT中进行某种操作时,对应的SPLAY会进行何种变化:

    splay 操作:没有改变任何一个节点的染色,SPLAY无变化。

    access 操作:我们看看它的具体代码:

    inline void access(int x){
    	for(register int y=0;x;x=t[y=x].fa)splay(x),rson=y,pushup(x);
    }
    

    我们在这里面改变了节点的染色!

    我们强制断开了 rson ,即将以 rson 为根的子树染成某种颜色;并将以 y 为根的子树染成和以 x 为根的子树的同一种颜色!

    对应的SPLAY中的操作就是:挖掉深度大于等于 rson 的所有节点,并将以 y 为根的SPLAY接上去。

    这个时候,我们便看出以深度为键值的好处了:只要记录一个 size 表示子树大小,我们就只需要找出SPLAY中排名为 lson_size+1 的点,断去它的右儿子,并将 y 赋成它新的右儿子即可。

    说一下下文代码中各函数的含义:

    lc :LCT。

    sp :SPLAY。

    rt[x] :节点\(x\)被染上的颜色。

    CHANGE(x,y):把以\(x\)为根的子树全都染成\(y\)颜色。

    fd(x,y):找到以\(x\)为根的子树中排名为\(y\)的节点,并将其转到\(root\)

    inline void access(int x){
    	for(register int y=0;x;x=lc.fa[y=x]){
    		lc.splay(x);
    		int xx=rt[x];
    		sp.splay(xx);
    		xx=sp.fd(xx,lc.sz[lc.ch[x][0]]+1);
    		lc.CHANGE(lc.ch[x][1],sp.ch[xx][1]);
    		lc.ch[x][1]=y;
    		lc.CHANGE(x,xx);
    		sp.fa[sp.ch[xx][1]]=0;
    		sp.ch[xx][1]=rt[y];
    		sp.fa[rt[y]]=xx;
    		lc.pushup(x),sp.pushup(xx);
    	}
    }
    

    access函数是最主要的函数。其它还有函数makerootsplit等。反正,就是splay怎样做,SPLAY就怎样做(至少大部分情况是这样,即影响SPLAY结构或染色的操作)。

    inline void makeroot(int x){
    	access(x),lc.splay(x),sp.splay(rt[x]),lc.REV(x),sp.REV(rt[x]);
    }
    inline void split(int x,int y){
    	makeroot(x),access(y),lc.splay(y),sp.splay(rt[y]);
    }
    inline void link(int x,int y){
    	makeroot(x),lc.fa[x]=y;
    }
    

    最终代码:

    #include<bits/stdc++.h>
    using namespace std;
    #define int long long
    int n,m,mn[100100],mx[100100],val[100100],sum[100100],tag[100100],rt[100100],tr[100100];
    struct SPLAY{
    	#define lson ch[x][0]
    	#define rson ch[x][1]
    	int fa[100100],ch[100100][2],sz[100100];
    	bool rev[100100],tp;
    	inline int identify(int x){
    		if(x==ch[fa[x]][0])return 0;
    		if(x==ch[fa[x]][1])return 1;
    		return -1;
    	}
    	inline void pushup(int x){
    		if(tp==0){
    			mn[x]=mx[x]=sum[x]=val[x],sz[x]=1;
    			if(lson)mx[x]=max(mx[x],mx[lson]),mn[x]=min(mn[x],mn[lson]),sz[x]+=sz[lson],sum[x]+=sum[lson];
    			if(rson)mx[x]=max(mx[x],mx[rson]),mn[x]=min(mn[x],mn[rson]),sz[x]+=sz[rson],sum[x]+=sum[rson];			
    		}else{
    			sz[x]=1;
    			if(lson)sz[x]+=sz[lson];
    			if(rson)sz[x]+=sz[rson];
    		}
    	}
    	inline void ADD(int x,int vv){
    		if(!x)return;
    		sum[x]+=vv*sz[x],mn[x]+=vv,mx[x]+=vv,tag[x]+=vv,val[x]+=vv;
    	}
    	inline void CHANGE(int x,int y){
    		if(!x)return;
    		rt[x]=tr[x]=y;
    	}
    	inline void REV(int x){
    		if(!x)return;
    		swap(lson,rson),rev[x]^=1;
    	}
    	inline void pushdown(int x){
    		if(!tp){
    			if(rev[x]){
    				if(lson)REV(lson);
    				if(rson)REV(rson);
    				rev[x]=0;
    			}
    			if(lson)ADD(lson,tag[x]);
    			if(rson)ADD(rson,tag[x]);
    			tag[x]=0;			
    		}else{
    			if(rev[x]){
    				if(lson)REV(lson);
    				if(rson)REV(rson);
    				rev[x]=0;			
    			}
    			if(tr[x]){
    				if(lson)CHANGE(lson,tr[x]);
    				if(rson)CHANGE(rson,tr[x]);
    				tr[x]=0;
    			}
    		}
    	}
    	inline void rotate(int x){
    		register int y=fa[x];
    		register int z=fa[y];
    		register int dirx=identify(x);
    		register int diry=identify(y);
    		register int b=ch[x][!dirx];
    		if(diry!=-1)ch[z][diry]=x;fa[x]=z;
    		if(b)fa[b]=y;ch[y][dirx]=b;
    		fa[y]=x,ch[x][!dirx]=y;
    		pushup(y),pushup(x);
    	}
    	inline void pushall(int x){
    		if(identify(x)!=-1)pushall(fa[x]);
    		pushdown(x);
    	}
    	inline void splay(int x){
    		pushall(x);
    		while(identify(x)!=-1){
    			register int Fa=fa[x];
    			if(identify(Fa)==-1)rotate(x);
    			else if(identify(x)==identify(Fa))rotate(Fa),rotate(x);
    			else rotate(x),rotate(x);
    		}
    	}
    	int fd(int x,int k){
    		while(true){
    			pushdown(x);
    			if(k<=sz[lson])x=lson;
    			else if(k>sz[lson]+1)k-=sz[lson]+1,x=rson;
    			else{splay(x);return x;}
    		}
    	}
    	#undef lson
    	#undef rson 
    }sp,lc;
    inline void access(int x){
    	for(register int y=0;x;x=lc.fa[y=x]){
    		lc.splay(x);
    		int xx=rt[x];
    		sp.splay(xx);
    		xx=sp.fd(xx,lc.sz[lc.ch[x][0]]+1);
    		lc.CHANGE(lc.ch[x][1],sp.ch[xx][1]);
    		lc.ch[x][1]=y;
    		lc.CHANGE(x,xx);
    		sp.fa[sp.ch[xx][1]]=0;
    		sp.ch[xx][1]=rt[y];
    		sp.fa[rt[y]]=xx;
    		lc.pushup(x),sp.pushup(xx);
    	}
    }
    inline void makeroot(int x){
    	access(x),lc.splay(x),sp.splay(rt[x]),lc.REV(x),sp.REV(rt[x]);
    }
    inline void split(int x,int y){
    	makeroot(x),access(y),lc.splay(y),sp.splay(rt[y]);
    }
    inline void link(int x,int y){
    	makeroot(x),lc.fa[x]=y;
    }
    inline int read(){
    	register int x=0;
    	register char c=getchar();
    	while(c>'9'||c<'0')c=getchar();
    	while(c>='0'&&c<='9')x=(x<<3)+(x<<1)+(c^48),c=getchar();
    	return x;
    }
    signed main(){
    	n=read(),m=read(),read(),lc.tp=true;
    	for(int i=1;i<=n;i++)rt[i]=i,lc.sz[i]=sp.sz[i]=1;
    	for(int i=1,x,y;i<n;i++)x=read(),y=read(),link(x,y);
    	for(int i=1,x,y,z;i<=m;i++){
    		char s[10];
    		scanf("%s",s),x=read(),y=read(),split(x,y);
    		if(s[2]=='c')z=read(),sp.ADD(rt[y],z);
    		if(s[2]=='m')printf("%lld\n",sum[rt[y]]);
    		if(s[2]=='j')printf("%lld\n",mx[rt[y]]);
    		if(s[2]=='n')printf("%lld\n",mn[rt[y]]);
    		if(s[2]=='v')sp.REV(rt[y]);
    	}
    	return 0;
    }
    

  • 相关阅读:
    springboot对JPA的支持
    springboot整合redis
    spring boot整合mybatis
    mybatis与spring集成
    mybatis动态sql和分页
    mybatis入门
    使用java代码操作redis
    Redis安装和基本操作
    idea安装及使用
    爬虫
  • 原文地址:https://www.cnblogs.com/Troverld/p/14602059.html
Copyright © 2011-2022 走看看