• BZOJ4573 : [Zjoi2016]大森林


    扫描线,从左到右依次处理每棵树。

    用set按时间顺序维护影响了这棵树的所有操作,那么一个点的父亲就是它前面第一个操作1。

    用Splay维护树的括号序列,那么两点间的距离就是括号数量减去匹配的括号个数。

    添加或删除操作0就是单点换父亲,添加或删除操作1就是区间换父亲。可以通过添加虚点来实现区间换父亲操作。

    时间复杂度$O(mlog m)$。

    #include<cstdio>
    #include<algorithm>
    #include<set>
    using namespace std;
    const int N=200010;
    int n,m,i,j,op,x,y,z,cnt,L[N],R[N],q[N+5][2],ans[N],tot,ap[N];
    int ga0[N],gd0[N],ga1[N],gd1[N],v[N<<1],nxt[N<<1],ed,G[N],V[N],W[N],NXT[N],cq;
    set<int>T0,T1;
    inline void read(int&a){char c;while(!(((c=getchar())>='0')&&(c<='9')));a=c-'0';while(((c=getchar())>='0')&&(c<='9'))(a*=10)+=c-'0';}
    inline void add(int&x,int y){v[++ed]=y;nxt[ed]=x;x=ed;}
    inline void addq(int x,int y,int z){V[++cq]=y;W[cq]=z;NXT[cq]=G[x];G[x]=cq;}
    namespace DS{
    const int M=N<<2;
    int son[M][2],f[M],size[M];
    struct P{
      int x,y;
      P(){x=y=0;}
      P(int _x,int _y){x=_x,y=_y;}
      inline P operator+(const P&v){return y>v.x?P(x,y-v.x+v.y):P(x+v.x-y,v.y);}
      inline void operator+=(const P&v){*this=*this+v;}
    }v[M],s[M];
    inline void up(int x){
      size[x]=size[son[x][0]]+size[son[x][1]]+1;
      s[x]=s[son[x][0]]+v[x]+s[son[x][1]];
    }
    inline void rotate(int x){
      int y=f[x],w=son[y][1]==x;
      son[y][w]=son[x][w^1];
      if(son[x][w^1])f[son[x][w^1]]=y;
      if(f[y]){
        int z=f[y];
        if(son[z][0]==y)son[z][0]=x;
        if(son[z][1]==y)son[z][1]=x;
      }
      f[x]=f[y];son[x][w^1]=y;f[y]=x;up(y);
    }
    inline void splay(int x,int w){
      while(f[x]!=w){
        int y=f[x];
        if(f[y]!=w){if((son[f[y]][0]==y)^(son[y][0]==x))rotate(x);else rotate(y);}
        rotate(x);
      }
      up(x);
    }
    void spilt(int x,int y){
      splay(x,0);splay(y,x);
      f[son[x][0]]=f[son[y][1]]=0;
      if(son[x][0]&&son[y][1]){
        int z=son[x][0];
        while(son[z][1])z=son[z][1];
        splay(z,0);
        son[z][1]=son[y][1];
        f[son[y][1]]=z;
        up(z);
      }
      son[x][0]=son[y][1]=0;
      up(y);up(x);
    }
    inline int rank(int x){
      splay(x,0);
      return size[son[x][0]];
    }
    inline int ask(int x,int y){
      splay(x,0);splay(y,x);
      P t=s[son[y][0]]+v[y];
      return t.x+t.y;
    }
    inline void addright(int x,int y){
      splay(x,0);
      x=son[x][1];
      while(son[x][0])x=son[x][0];
      son[x][0]=y;
      f[y]=x;
      up(x);
      splay(y,0);
    }
    inline void newnode(int o,int val,int z){
      int x=o<<1,y=x|1;
      v[x]=P(0,val),v[y]=P(val,0);
      f[y]=x,son[x][1]=y;
      up(y);up(x);
      if(z)addright(z<<1,x);
    }
    }
    inline void add0(int x){
      int y=q[x][1];
      set<int>::iterator j=T0.lower_bound(x);
      j--;
      DS::spilt(y<<1,y<<1|1);
      if(q[*j][0])DS::addright(q[*j][1]<<1,y<<1);
      else DS::addright(q[*j][1]<<1|1,y<<1);
      T0.insert(x);
    }
    inline void del0(int x){
      int y=q[x][1];
      T0.erase(x);
      DS::spilt(y<<1,y<<1|1);
    }
    inline void add1(int x){
      int y=q[x][1];
      set<int>::iterator j=T0.lower_bound(x),k;
      if(*j<N&&!q[*j][0]){
        k=T1.lower_bound(x);
        k=T0.find(*k);
        k--;
        DS::spilt(q[*j][1]<<1,q[*k][1]<<1|1);
        DS::addright(y<<1,q[*j][1]<<1);
      }
      T0.insert(x);
      T1.insert(x);
    }
    inline void del1(int x){
      int y=q[x][1],pos;
      T0.erase(x);
      T1.erase(x);
      set<int>::iterator j=T0.lower_bound(x),k,o;
      if(*j<N&&!q[*j][0]){
        k=T1.lower_bound(x);
        k=T0.find(*k);
        k--;
        o=T0.lower_bound(x);
        o--;
        DS::spilt(q[*j][1]<<1,q[*k][1]<<1|1);
        if(q[*o][0])DS::addright(q[*o][1]<<1,q[*j][1]<<1);
        else DS::addright(q[*o][1]<<1|1,q[*j][1]<<1);
      }
    }
    inline int query(int x,int y){
      if(x==y)return 0;
      if(DS::rank(x<<1)>DS::rank(y<<1))swap(x,y);
      return DS::ask(x<<1,y<<1);
    }
    int main(){
      read(n),read(m);
      L[cnt=1]=1,R[1]=n;
      q[0][0]=q[0][1]=1;
      for(i=1;i<=m+1;i++){
        ap[i]=i;
        DS::newnode(i,1,0);
      }
      tot=m+1;
      for(i=1;i<=m;i++){
        read(op),read(x),read(y);
        if(!op){
          L[++cnt]=x;R[cnt]=y;
          q[i][1]=cnt;
          add(ga0[x],i),add(gd0[y],i);
        }
        if(op==1){
          read(z);
          x=max(x,L[z]),y=min(y,R[z]);
          if(x>y)continue;
          DS::newnode(++tot,0,ap[z]);
          ap[z]=tot;
          q[i][0]=1,q[i][1]=tot;
          add(ga1[x],i),add(gd1[y],i);
        }
        if(op==2)read(z),addq(x,y,z);
      }
      T0.insert(0),T0.insert(N);
      T1.insert(0),T1.insert(N);
      for(i=1;i<=n;i++){
        for(j=ga0[i];j;j=nxt[j])add0(v[j]);
        for(j=ga1[i];j;j=nxt[j])add1(v[j]);
        for(j=G[i];j;j=NXT[j])ans[j]=query(V[j],W[j]);
        for(j=gd0[i];j;j=nxt[j])del0(v[j]);
        for(j=gd1[i];j;j=nxt[j])del1(v[j]);
      }
      for(i=1;i<=cq;i++)printf("%d
    ",ans[i]);
      return 0;
    }
    

      

  • 相关阅读:
    flexbox弹性盒子布局
    LAMP环境 源码包安装
    用条件注释判断浏览器版本,解决兼容问题
    事件冒泡和事件捕获
    为js和css文件自动添加版本号
    uEditor独立图片上传
    修改netbeans模版头部的说明
    thinkphp多表关联并且分页
    thinkphp 独立分组配置
    荣耀路由HiLink一键组网如何实现?
  • 原文地址:https://www.cnblogs.com/clrs97/p/5490949.html
Copyright © 2020-2023  润新知