hdu 3487 Play with Chain(splay区间剪切,翻转)

题目链接:hdu 3487 Play with Chain

题意:

cut a b c:

将a到b区间剪切下来,放在第c位置的后面。

flip a b:

翻转a到b区间

题解:

第一个操作,选通过旋转,然后使a到b区间变成根的右儿子的左儿子,然后剪掉。

再找到c+1的位置,接上。

第二个操作,区间标记就行。

  1 #include<bits/stdc++.h>
  2 #define F(i,a,b) for(int i=a;i<=b;++i)
  3 using namespace std;
  4 const int N=1e6+7;
  5 int _t;
  6
  7 struct Splay_tree
  8 {
  9     int root,q[N];bool rev[N];
 10     int key[N],sz[N],f[N],ch[N][2];
 11     void rev1(int x){if(x)swap(ch[x][0],ch[x][1]),rev[x]^=1;}
 12     inline void nw(int &x,int val,int fa)
 13     {
 14         x=++_t,key[x]=val,f[x]=fa,sz[x]=1;
 15         ch[x][0]=ch[x][1]=0;
 16         rev[x]=0;
 17     }
 18     inline void pd(int x){if(rev[x])rev1(ch[x][0]),rev1(ch[x][1]),rev[x]=0;}
 19     inline void up(int x){sz[x]=sz[ch[x][0]]+sz[ch[x][1]]+1;}
 20     void rotate(int x){
 21         int y=f[x],w=ch[y][1]==x;
 22         ch[y][w]=ch[x][w^1];
 23         if(ch[x][w^1])f[ch[x][w^1]]=y;
 24         if(f[y]){
 25             int z=f[y];
 26             if(ch[z][0]==y)ch[z][0]=x;
 27             if(ch[z][1]==y)ch[z][1]=x;
 28         }
 29         f[x]=f[y],ch[x][w^1]=y,f[y]=x,up(y);
 30     }
 31     void splay(int x,int w){
 32         int s=1,i=x,y;q[1]=x;
 33         while(f[i])q[++s]=i=f[i];
 34         while(s)pd(q[s--]);
 35         while(f[x]!=w){
 36             y=f[x];
 37             if(f[y]!=w){if((ch[f[y]][0]==y)^(ch[y][0]==x))rotate(x);else rotate(y);}
 38             rotate(x);
 39         }
 40         if(!w)root=x;
 41         up(x);
 42     }
 43     void build(int &x,int l,int r,int fa=0)//按照数组下标建树
 44     {
 45         if(l>r)return;
 46         int mid=l+r>>1;
 47         nw(x,mid,fa);
 48         build(ch[x][0],l,mid-1,x);
 49         build(ch[x][1],mid+1,r,x);
 50         up(x);
 51     }
 52     inline int kth(int k)//获得第k小
 53     {
 54         if(k>sz[root]||k<=0)return 0;
 55         int x=root,tmp;
 56         while(1)
 57         {
 58             pd(x),tmp=sz[ch[x][0]]+1;
 59             if(k==tmp)break;
 60             if(k<tmp)x=ch[x][0];else k-=tmp,x=ch[x][1];
 61         }
 62         return x;
 63     }
 64     void reverse(int a,int b)//翻转a到b区间
 65     {
 66         splay(kth(a),0),splay(kth(b+2),root);
 67         rev1(ch[ch[root][1]][0]);
 68     }
 69     void cut(int a,int b,int c)
 70     {
 71         splay(kth(a),0),splay(kth(b+2),root);
 72         int tmp=ch[ch[root][1]][0];
 73         ch[ch[root][1]][0]=0;
 74         pd(ch[root][1]),pd(root);
 75         splay(kth(c+1),0);
 76         splay(kth(c+2),root);
 77         ch[ch[root][1]][0]=tmp;
 78         f[ch[ch[root][1]][0]]=ch[root][1];
 79         up(ch[root][1]),up(root);
 80     }
 81 }spt;
 82 //--------------------------------
 83
 84 int n,m,cnt;
 85
 86 void out(int x)
 87 {
 88     if(!x)return;
 89     spt.pd(x),out(spt.ch[x][0]);
 90     if(spt.key[x]>1&&spt.key[x]<n+2)printf("%d%c",spt.key[x]-1," \n"[++cnt==n]);
 91     out(spt.ch[x][1]);
 92 }
 93
 94 int main()
 95 {
 96     while(~scanf("%d%d",&n,&m))
 97     {
 98         if(n==-1)break;
 99         _t=0,spt.build(spt.root,1,n+2);
100         char cmd[10];
101         int a,b,c;
102         F(i,1,m)
103         {
104             scanf("%s",cmd);
105             if(cmd[0]==‘C‘)
106             {
107                 scanf("%d%d%d",&a,&b,&c);
108                 spt.cut(a,b,c);
109             }else scanf("%d%d",&a,&b),spt.reverse(a,b);
110         }
111         cnt=0,out(spt.root);
112     }
113     return 0;
114 }

时间: 2024-10-11 14:49:11

hdu 3487 Play with Chain(splay区间剪切,翻转)的相关文章

hdu 3487 Play with Chain (Splay)

hdu 3487 Splay树模板题 题意: 一开始给出1 2 3 4 ... n 这样一个序列,对这个序列进行以下两种操作: (1)CUT a b c: 将子串[a,b]切下来,放到剩余串的第c个数之后 . (2) FLIP a b : 将子串[a,b]翻转,如 1 2 3 4 就变成 4 3 2 1 . 总之就是一道Splay树的模板题 ... 1 #include <iostream> 2 #include <cstdio> 3 #include <algorithm&

HDU 3487 Play with Chain 【Splay】

1-n的序列,有两种操作: 1,将一段区间翻转 2,将一段区间切下来放到剩余序列的第C个数后 采用延迟更新的方法维护区间的翻转,并维护一个size域. 添加一个最大点和一个最小点,防止出界 翻转时,将第L-1个点伸展到跟,再将第R+1个点伸展到L-1的右子树,这时R+1的左子树就是要翻转的区间,加上一个标记. 切区间时,跟翻转操作差不多,只是不加标记.然后找到C+1和C,将C伸展到根,C+1伸展到C的右子树,此时C+1的左子树就是要插入的位置. 其实我说了这么多并没有什么卵用....最后还是得自

hdu 3487 Play with Chain

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3487 YaoYao is fond of playing his chains. He has a chain containing n diamonds on it. Diamonds are numbered from 1 to n.At first, the diamonds on the chain is a sequence: 1, 2, 3, …, n.He will perform t

Splay树——HDU 3487 Play with Chain

对应HDU题目:点击打开链接 Play with Chain Time Limit: 6000/2000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 4571    Accepted Submission(s): 1859 Problem Description YaoYao is fond of playing his chains. He has a chain cont

【HDU 3487】Play with Chain Splay

题意 给定$n$个数序列,每次两个操作,将区间$[L,R]$拼接到去掉区间后的第$c$个数后,或者翻转$[L,R]$ Splay区间操作模板,对于区间提取操作,将$L-1$ Splay到根,再将$R+1$ Splay到根节点的右儿子,那么根节点右儿子的左儿子就对应区间$[L,R]$,对于反转操作,通过懒操作下放 代码 #include <bits/stdc++.h> #define inf 0x7f7f7f7f using namespace std; const int N = 500005

hdu 1890 Robotic Sort(splay 区间反转+删点)

题目链接:hdu 1890 Robotic Sort 题意: 给你n个数,每次找到第i小的数的位置,然后输出这个位置,然后将这个位置前面的数翻转一下,然后删除这个数,这样执行n次. 题解: 典型的splay区间翻转+删点. 我们把数据排序,然后记录一下每个数原来的位置,然后splay建树的时候用原来的位置来对应,这样val[i].second就直接是这个数在splay中的那个节点. (当然你也可以普通建树,然后手动记录位置). 然后我们把要找的那个数对应的节点旋转到根,然后根左边的size+i就

hdu3487Play with Chain(splay)

链接 简单的两种操作,一种删除某段区间,加在第I个点的后面,另一个是翻转区间.都是splay的简单操作. 悲剧一:pushdown时候忘记让lz=0 悲剧二:删除区间,加在某点之后的时候忘记修改其父亲节点. 1 #include <iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 #include<stdlib.h> 6 #include<vec

UVA 11922 Splay区间翻转+分裂+合并

- Permutation Transformer Time Limit:2000MS     Memory Limit:0KB     64bit IO Format:%lld & %llu Submit Status Practice UVA 11922 Appoint description:  System Crawler  (2014-11-30) Description  Permutation Transformer  Write a program to transform th

算法模板——splay区间反转 2

实现功能:同splay区间反转 1(基于BZOJ3223 文艺平衡树) 这次改用了一个全新的模板(HansBug:琢磨了我大半天啊有木有),大大简化了程序,同时对于splay的功能也有所完善 这里面没有像一般二叉排序树那样子用一个参量进行排序,而是直接以中序遍历来构建了一个普通的二叉树(当然也可以把每个点的中序遍历排名视作参量),然后插入的时候就是指定位置插入(这个就比较像是文本插入了) 总之得到了较大的提升,代码优美程度也提高不少 1 var 2 i,j,k,l,m,n,head,tot,ll