zoukankan      html  css  js  c++  java
  • BZOJ4817 [Sdoi2017]树点涂色

    本文版权归ljh2000和博客园共有,欢迎转载,但须保留此声明,并给出原文链接,谢谢合作。

    本文作者:ljh2000
    作者博客:http://www.cnblogs.com/ljh2000-jump/
    转载请注明出处,侵权必究,保留最终解释权!

    题目链接:BZOJ4817

    正解:$LCT$+线段树

    解题报告:

      考虑操作$1$很类似$LCT$中的$access$操作,我们可以借助$LCT$的复杂度证明,来保证用$LCT$的实现方式来完成本题的操作复杂度的正确性。

      我们维护每个点到根的权值,用线段树维护$dfs$序上的区间最值查询,做之前先把$1$变成根,再$access(x)$,那么不难发现$access$的时候只有在轻重边切换(也就是染成同一颜色的操作发生)的时候才需要改颜色,相当于是把原来的儿子节点所在的子树权值$+1$,现在的$-1$,这个用线段树区间修改就好了。

      有一点要注意的就是搞清楚修改的对象,需要在$LCT$上沿着左子树往下走,根据性质很容易想清楚。

      操作$2$的话,画一画发现答案就是$x$的权值$+y$的权值$-2*lca$的权值$+1$,这个跟$SDOI$以前的某道线段树的题目类似。

      操作$3$就直接线段树区间查询就完了。

     

    //It is made by ljh2000
    //有志者,事竟成,破釜沉舟,百二秦关终属楚;苦心人,天不负,卧薪尝胆,三千越甲可吞吴。
    #include <algorithm>
    #include <iostream>
    #include <cstring>
    #include <vector>
    #include <cstdio>
    #include <string>
    #include <queue>
    #include <cmath>
    #include <ctime>
    using namespace std;
    typedef long long LL;
    const int MAXN = 200011;
    const int MAXM = 200011;
    int n,m,ecnt,first[MAXN],to[MAXM],nxt[MAXM],ans,deep[MAXN],dfn[MAXN],end[MAXN],f[MAXN][18],pre[MAXN],father[MAXN];
    
    //1:access,轻重边切换的时候顺便modify一下实儿子的权值
    //2:a_x+a_y-2*a_{lca(x,y)}+1
    //3:直接查询
    
    inline void link(int x,int y) { nxt[++ecnt]=first[x]; first[x]=ecnt; to[ecnt]=y; }
    inline void build(){ for(int j=1;j<=17;j++) for(int i=1;i<=n;i++) f[i][j]=f[f[i][j-1]][j-1]; }
    inline int getint(){
        int w=0,q=0; char c=getchar(); while((c<'0'||c>'9') && c!='-') c=getchar();
        if(c=='-') q=1,c=getchar(); while (c>='0'&&c<='9') w=w*10+c-'0',c=getchar(); return q?-w:w;
    }
    
    inline void dfs(int x,int fa){
    	dfn[x]=++ecnt; pre[ecnt]=x;
    	for(int i=first[x];i;i=nxt[i]) {
    		int v=to[i]; if(v==fa) continue; deep[v]=deep[x]+1;
    		f[v][0]=father[v]=x; dfs(v,x);
    	}
    	end[x]=ecnt;
    }
    
    inline int lca(int x,int y){
    	if(deep[x]<deep[y]) swap(x,y); int t=0; while((1<<t)<=deep[x]) t++; t--;
    	for(int i=t;i>=0;i--) if(deep[x]-(1<<i)>=deep[y]) x=f[x][i]; if(x==y) return x;
    	for(int i=t;i>=0;i--) if(f[x][i]!=f[y][i]) x=f[x][i],y=f[y][i]; return f[x][0];
    }
    
    namespace Tree{
    #define lc root<<1
    #define rc root<<1|1
    	int maxl[MAXN*3],tag[MAXN*3];
    	inline void build(int root,int l,int r){
    		if(l==r) { maxl[root]=deep[pre[l]]; return ; }
    		int mid=(l+r)>>1; build(lc,l,mid); build(rc,mid+1,r);
    		maxl[root]=max(maxl[lc],maxl[rc]);
    	}
    
    	inline void pushdown(int root,int l,int r){
    		if(tag[root]==0 || l==r) return ;
    		tag[lc]+=tag[root]; tag[rc]+=tag[root];
    		maxl[lc]+=tag[root]; maxl[rc]+=tag[root];
    		tag[root]=0;
    	}
    
    	inline void modify(int root,int l,int r,int ql,int qr,int val){
    		pushdown(root,l,r);
    		if(ql<=l && r<=qr) { tag[root]+=val; maxl[root]+=val; return ; }
    		int mid=(l+r)>>1;
    		if(ql<=mid) modify(lc,l,mid,ql,qr,val);
    		if(qr>mid) modify(rc,mid+1,r,ql,qr,val);
    		maxl[root]=max(maxl[lc],maxl[rc]);
    	}
    
    	inline int query(int root,int l,int r,int ql,int qr){
    		pushdown(root,l,r);
    		if(ql<=l && r<=qr) return maxl[root];
    		int mid=(l+r)>>1;
    		if(ql>mid) return query(rc,mid+1,r,ql,qr);
    		else if(qr<=mid) return query(lc,l,mid,ql,qr);
    		else return max( query(lc,l,mid,ql,qr) , query(rc,mid+1,r,ql,qr) );
    	}
    }
    
    namespace LCT{
    	int stack[MAXN],top,tr[MAXN][2],tag[MAXN];
    	inline bool isroot(int x){ return (tr[father[x]][0]!=x) && (tr[father[x]][1]!=x); }
    	inline void pushdown(int x){
    		if(tag[x]==0) return ;
    		int l=tr[x][0],r=tr[x][1];
    		if(l) tag[l]^=1; if(r) tag[r]^=1;
    		swap(tr[x][0],tr[x][1]); tag[x]=0;
    	}
    
    	inline void rotate(int x){
    		int y,z,l,r; y=father[x]; z=father[y]; l=(tr[y][1]==x); r=l^1;
    		if(!isroot(y)) tr[z][(tr[z][1]==y)]=x;
    		father[x]=z; father[y]=x;
    		tr[y][l]=tr[x][r]; father[tr[x][r]]=y; tr[x][r]=y;
    	}
    
    	inline void splay(int x){
    		int y,z; top=0; stack[++top]=x;
    		for(int i=x;!isroot(i);i=father[i]) stack[++top]=father[i];
    		for(int i=top;i>=1;i--) pushdown(stack[i]);
    		while(!isroot(x)) {
    			y=father[x]; z=father[y];
    			if(!isroot(y)) {
    				if((tr[z][0]==y) ^ (tr[y][0]==x)) rotate(x);
    				else rotate(y);
    			}
    			rotate(x);
    		}
    	}
    
    	inline int getL(int x){
    		if(!x) return 0;
    		while(x) {
    			if(tr[x][0]) x=tr[x][0];
    			else break;
    		}
    		return x;
    	}
    
    	inline void access(int x){
    		int last=0,pos;
    		while(x) {
    			splay(x);
    
    			pos=getL(tr[x][1]);
    			if(pos) Tree::modify(1,1,n,dfn[pos],end[pos],1);
    			tr[x][1]=last;
    
    			pos=getL(last);
    			if(pos) Tree::modify(1,1,n,dfn[pos],end[pos],-1);
    
    			last=x; x=father[x];
    		}
    	}
    
    	inline void move_to_root(int x){
    		access(x);
    		splay(x);
    		tag[x]^=1;
    	}
    }
    
    inline void work(){
    	n=getint(); m=getint(); int x,y,type,LCA;
    	for(int i=1;i<n;i++) { x=getint(); y=getint(); link(x,y); link(y,x); }
    	deep[1]=1; ecnt=0; dfs(1,0); 
    	build(); 
    	Tree::build(1,1,n);
    	while(m--) {
    		type=getint(); x=getint();
    		if(type==1) {
    			LCT::move_to_root(1);
    			LCT::access(x);
    		}
    		else if(type==2) {
    			ans=0; y=getint();
    			ans+=Tree::query(1,1,n,dfn[x],dfn[x]);
    			ans+=Tree::query(1,1,n,dfn[y],dfn[y]);
    			LCA=lca(x,y);
    			ans-=2*Tree::query(1,1,n,dfn[LCA],dfn[LCA]);
    			ans++;
    			printf("%d
    ",ans);
    		}
    		else {
    			ans=Tree::query(1,1,n,dfn[x],end[x]);
    			printf("%d
    ",ans);
    		}
    	}
    }
    
    int main()
    {
    #ifndef ONLINE_JUDGE
    	freopen("paint.in","r",stdin);
    	freopen("paint.out","w",stdout);
    #endif
        work();
        return 0;
    }
    //有志者,事竟成,破釜沉舟,百二秦关终属楚;苦心人,天不负,卧薪尝胆,三千越甲可吞吴。
    

      

  • 相关阅读:
    PHP date 格式化一个本地时间/日期
    Unix时间戳(Unix timestamp)转换工具
    Ubuntu下搭建NodeJS+Express WEB开发框架
    高手指南PHP安装配置
    thinkphp系统常量与自定义常量
    UDP 构建p2p打洞过程的实现原理(持续更新)
    iOS标准时间与时间戳相互转换
    java 时间戳和PHP时间戳 的转换
    Windows与Linux/Mac系统时间不一致的解决方法
    推荐25款php中非常有用的类库
  • 原文地址:https://www.cnblogs.com/ljh2000-jump/p/6810316.html
Copyright © 2011-2022 走看看