zoukankan      html  css  js  c++  java
  • bzoj 4573: [Zjoi2016]大森林

    Description

    小Y家里有一个大森林,里面有n棵树,编号从1到n。一开始这些树都只是树苗,只有一个节点,标号为1。这些树
    都有一个特殊的节点,我们称之为生长节点,这些节点有生长出子节点的能力。小Y掌握了一种魔法,能让第l棵树
    到第r棵树的生长节点长出一个子节点。同时她还能修改第l棵树到第r棵树的生长节点。她告诉了你她使用魔法的
    记录,你能不能管理她家的森林,并且回答她的询问呢?

    Solution

    有点神仙,看了题解的做法
    首先显然要离线,否则空间都是错的,这样维护一棵树就好了
    然后发现都是区间修改,扫描线维护一下节点就好了
    但是还有删除节点这样的操作,复杂度保证不了

    不如先把树的形态都建出来,对于 (1)(n) 的公共部分我们一起考虑,不同的部分就直接新建节点
    考虑维护添加,删除操作的复杂度
    我们每产生一个新的生长节点就新建一个虚点,然后把新长出来的都接上去
    如果按加入时间考虑的话,有很多连续的节点都是同一个父亲,所以我们用一个虚点暂时代替它们的父亲
    然后对于 (1)(n) 的不同的树,它们的父亲是不一样的,因为建立了这个虚点,所以只需要把虚点的父亲变一下,就可以达到把所有的点的父亲都改变的效果了

    具体的也说不清楚,看代码比较直观.....

    #include<bits/stdc++.h>
    using namespace std;
    template<class T>void gi(T &x){
    	int f;char c;
    	for(f=1,c=getchar();c<'0'||c>'9';c=getchar())if(c=='-')f=-1;
    	for(x=0;c<='9'&&c>='0';c=getchar())x=x*10+(c&15);x*=f;
    }
    const int N=4e5+10;
    int n,m,ch[N][2],fa[N],a[N],w[N];
    inline void upd(int x){w[x]=w[ch[x][0]]+w[ch[x][1]]+a[x];}
    inline bool isrt(int x){return ch[fa[x]][0]!=x&&ch[fa[x]][1]!=x;}
    inline void rotate(int x){
    	int y=fa[x];bool t=ch[y][1]==x;
    	ch[y][t]=ch[x][!t];fa[ch[y][t]]=y;
    	ch[x][!t]=y;fa[x]=fa[y];
    	if(!isrt(y))ch[fa[y]][ch[fa[y]][1]==y]=x;
    	fa[y]=x;upd(y);upd(x);
    }
    inline void splay(int x){
    	while(!isrt(x)){
    		int y=fa[x],p=fa[y];
    		if(isrt(y))rotate(x);
    		else if((ch[p][0]==y)==(ch[y][0]==x))rotate(y),rotate(x);
    		else rotate(x),rotate(x);
    	}
    }
    inline int access(int x){
    	int y=0;
    	while(x)splay(x),ch[x][1]=y,upd(x),x=fa[y=x];
    	return y;
    }
    inline void link(int x,int y){
    	access(x);splay(x);fa[x]=y;
    }
    inline void cut(int x){
    	access(x);splay(x);fa[ch[x][0]]=0;ch[x][0]=0;upd(x);
    }
    inline int query(int x,int y){
    	int ret=0,t;
    	access(x);splay(x);ret+=w[x];
    	t=access(y);splay(y);ret+=w[y];
    	access(t);splay(t);ret-=w[t]<<1;
    	return ret;
    }
    int L[N],R[N],id[N],cnt=2,ans[N],top=0;
    struct data{
    	int ty,p,x,y;
    	inline bool operator <(const data &t)const{
    		if(p!=t.p)return p<t.p;
    		return ty<t.ty;
    	}
    }q[N];
    int main(){
      freopen("pp.in","r",stdin);
      freopen("pp.out","w",stdout);
      cin>>n>>m;
      int op,l,r,x,y=2,tp=0,ID=1;
      L[1]=1;R[1]=n;id[1]=1;w[1]=a[1]=1;
      L[2]=1;R[2]=n;w[2]=a[2]=0;link(2,1);
      for(int i=1;i<=m;i++){
    	  gi(op);gi(l);gi(r);
    	  if(op==0){
    		  a[++cnt]=1;w[cnt]=1;L[++ID]=l;R[ID]=r;id[ID]=cnt;
    		  link(cnt,y);
    	  }
    	  else if(op==1){
    		  gi(x);
    		  a[++cnt]=0;w[cnt]=0;l=max(l,L[x]);r=min(r,R[x]);
    		  if(l<=r){
    			  link(cnt,y);
    			  q[++top]=(data){-1,l,cnt,id[x]};
    			  q[++top]=(data){-1,r+1,cnt,y};
    			  y=cnt;
    		  }
    	  }
    	  else gi(x),q[++top]=(data){++tp,l,id[r],id[x]};
      }
      sort(q+1,q+top+1);
      for(int i=1,j=1;i<=n;i++){
    	  while(j<=top && q[j].p==i){
    		  if(q[j].ty==-1)cut(q[j].x),link(q[j].x,q[j].y);
    		  else ans[q[j].ty]=query(q[j].x,q[j].y);
    		  j++;
    	  }
      }
      for(int i=1;i<=tp;i++)printf("%d
    ",ans[i]);
      return 0;
    }
    
    
  • 相关阅读:
    LeetCode153.寻找旋转排序数组中的最小值
    LeetCode88.合并两个有序数组
    分析树
    LeetCode119.杨辉三角 II
    ssh传输文件
    ubuntu arm妙算加载cp210x驱动
    terminator终端工具
    ros使用rplidar hector_mapping建地图
    launch文件
    eclipse配置ros cakin编译环境
  • 原文地址:https://www.cnblogs.com/Yuzao/p/8968717.html
Copyright © 2011-2022 走看看