UVA 11922(用splay实现可分裂和合并的序列)

介绍一下,splay保存的序列,序列不再是有序的,只是维持相对位置,splay主要实现对第k个位置的元素旋转到根,然后实现分裂与合并,要实现找到第k个元素,就必须维护一个s(以该节点为根的子树有多少节点)。

对于本题目而言,要实现翻转,可以类比线段树来加惰性标志,实现翻转。

#include <cstdlib>
#include <algorithm>
#include <iostream>
#define rep1(i,x,y) for(int i=x;i<=y;i++)
typedef struct node* pointer;
struct node{
  pointer ch[2];
  int v,s,flip;
  node(int v=0):v(v){ch[0]=ch[1]=NULL; s=1; flip = 0; }
  int cmp(int x){
     int pre = (ch[0]==NULL ? 0 : ch[0]->s);
     if(pre + 1 == x) return -1;
     return pre>= x ? 0 : 1;
  }
  void maintain(){
     s = 1;
     if(ch[0]!=NULL) s+=ch[0]->s;
     if(ch[1]!=NULL) s+=ch[1]->s;
  }
  void pushdown(){
     if(flip){
         flip=0;
         std::swap(ch[0],ch[1]);
         if(ch[0] != NULL) ch[0]->flip ^= 1;
         if(ch[1] != NULL) ch[1]->flip ^= 1;
     }
  }
};
pointer root;
void init(int n){
   root = new node(1);
   pointer u = root; u->s = n;
   rep1(i,2,n){
      u->ch[1] = new node(i);
      u->ch[1]->s = n-i+1;
      u = u->ch[1];
   }
}
void rotate(pointer& o,int d){
   pointer te = o->ch[d^1];
   o->ch[d^1] = te->ch[d];
   te->ch[d] = o;
   o->maintain(); te->maintain();
   o = te;
}
void splay(pointer& o ,int k){
   o->pushdown();
   int d = o->cmp(k);
   if(d != -1){
      if(d==1) k -= (o->ch[0]==NULL ? 0 : o->ch[0]->s) + 1;
      o->ch[d]->pushdown();
      pointer te = o->ch[d];
      int d2  = te->cmp(k);
      if(d2!=-1){
          int k2 = (d2 == 0 ? k : k-(te->ch[0]==NULL ? 0 : te->ch[0]->s)-1);
          splay(te->ch[d2],k2);
          if(d2 == d) rotate(o,d^1);
          else rotate(o->ch[d],d);
      }
      rotate(o,d^1);
   }
}
pointer merge_(pointer le, pointer ri){
   splay(le,le->s);
   le->ch[1] = ri;
   le->maintain();
   return le;
}
void split(pointer o,int k,pointer &le , pointer &ri){
   splay(o,k);
   le = o;
   ri = o->ch[1];
   le->ch[1] = NULL;
   le->maintain();
}
#include <cstdio>
#include <algorithm>
#include <cstring>
#define rep(i,n) for(int i=0;i<(int)n;i++)
#define out(str) std::cout<<str<<std::endl;
typedef long long ll;
const int N = 2e4 + 100;
const int M = 6e4 + 100;

int n,m;
void dfs(pointer u){
   u->pushdown();
   if(u->ch[0] != NULL) dfs(u->ch[0]);
   if(u->v > 1)printf("%d\n",u->v-1);
   if(u->ch[1] != NULL) dfs(u->ch[1]);
}
int main()
{
   scanf("%d %d",&n,&m);
   init(n+1);
   int a, b;
   while(m--){
      scanf("%d %d",&a,&b);
      pointer le , mid , ri , o;
      split(root , a , le , o);
      split(o , b-a+1, mid , ri);
      mid->flip ^= 1;
      root = merge_(merge_(le,ri), mid);
   }
   dfs(root);
   return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值