HDU3487 Play With Chain [Splay]
Posted H
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了HDU3487 Play With Chain [Splay]相关的知识,希望对你有一定的参考价值。
题目描述
Problem Description
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 two types of operations:
CUT a b c: He will first cut down the chain from the ath diamond to the bth diamond. And then insert it after the cth diamond on the remaining chain.
For example, if n=8, the chain is: 1 2 3 4 5 6 7 8; We perform “CUT 3 5 4”, Then we first cut down 3 4 5, and the remaining chain would be: 1 2 6 7 8. Then we insert “3 4 5” into the chain before 5th diamond, the chain turns out to be: 1 2 6 7 3 4 5 8.
FLIP a b: We first cut down the chain from the ath diamond to the bth diamond. Then reverse the chain and put them back to the original position.
For example, if we perform “FLIP 2 6” on the chain: 1 2 6 7 3 4 5 8. The chain will turn out to be: 1 4 3 7 6 2 5 8
He wants to know what the chain looks like after perform m operations. Could you help him?
At first, the diamonds on the chain is a sequence: 1, 2, 3, …, n.
He will perform two types of operations:
CUT a b c: He will first cut down the chain from the ath diamond to the bth diamond. And then insert it after the cth diamond on the remaining chain.
For example, if n=8, the chain is: 1 2 3 4 5 6 7 8; We perform “CUT 3 5 4”, Then we first cut down 3 4 5, and the remaining chain would be: 1 2 6 7 8. Then we insert “3 4 5” into the chain before 5th diamond, the chain turns out to be: 1 2 6 7 3 4 5 8.
FLIP a b: We first cut down the chain from the ath diamond to the bth diamond. Then reverse the chain and put them back to the original position.
For example, if we perform “FLIP 2 6” on the chain: 1 2 6 7 3 4 5 8. The chain will turn out to be: 1 4 3 7 6 2 5 8
He wants to know what the chain looks like after perform m operations. Could you help him?
输入格式
Input
There will be multiple test cases in a test data.
For each test case, the first line contains two numbers: n and m (1≤n, m≤3*100000), indicating the total number of diamonds on the chain and the number of operations respectively.
Then m lines follow, each line contains one operation. The command is like this:
CUT a b c // Means a CUT operation, 1 ≤ a ≤ b ≤ n, 0≤ c ≤ n-(b-a+1).
FLIP a b // Means a FLIP operation, 1 ≤ a < b ≤ n.
The input ends up with two negative numbers, which should not be processed as a case.
Then m lines follow, each line contains one operation. The command is like this:
CUT a b c // Means a CUT operation, 1 ≤ a ≤ b ≤ n, 0≤ c ≤ n-(b-a+1).
FLIP a b // Means a FLIP operation, 1 ≤ a < b ≤ n.
The input ends up with two negative numbers, which should not be processed as a case.
输出格式
Output
For each test case, you should print a line with n numbers. The ith number is the number of the ith diamond on the chain.
样例
Sample Input
8 2
CUT 3 5 4
FLIP 2 6
-1 -1
Sample Output
1 4 3 7 6 2 5 8
分析:
题目大意就是给你一个数列1,2,3,...n,然后有两种操作,一种是将一段区间取下来再接到另一个位置,另一种是区间反转。
不难看出这是一道平衡树的题目,题目中的区间反转操作很明显的是Splay,用下放标记的方法很容易实现。再看另一种操作,要求将一段数列截下来然后放入另一段中,这个其实可以旋转以后把要移动的一段直接取下,然后在重新调整平衡树,记录要放入的区间的右端点,再把要放入的区间的左端点作为树根,把截下来的一段直接放上去,再调整,把右端点也接上去就可以了。具体在代码中注释。
Code:
1 #include<cstdio> 2 #include<cstring> 3 #include<cstdlib> 4 #include<cmath> 5 #include<iomanip> 6 #include<iostream> 7 #include<algorithm> 8 using namespace std; 9 const int N=3e5+7; 10 int n,m,root,tot; 11 int cnt,ans[N]; 12 struct Node{ 13 int ch[2],val,fa; 14 int size,mark; 15 void add(int x,int father){ 16 mark=ch[0]=ch[1]=0; 17 fa=father;val=x;size=1;} 18 }t[N]; 19 inline int read() 20 { 21 char ch=getchar();int num=0;bool flag=false; 22 while(ch<‘0‘||ch>‘9‘){if(ch==‘-‘)flag=true;ch=getchar();} 23 while(ch>=‘0‘&&ch<=‘9‘){num=num*10+ch-‘0‘;ch=getchar();} 24 return flag?-num:num; 25 } 26 inline void pushup(int x) 27 { 28 int l=t[x].ch[0],r=t[x].ch[1]; 29 t[x].size=t[l].size+t[r].size+1; 30 } 31 inline void pushdown(int x) 32 { 33 if(t[x].mark){ 34 t[t[x].ch[0]].mark^=1; 35 t[t[x].ch[1]].mark^=1; 36 swap(t[x].ch[0],t[x].ch[1]); 37 t[x].mark=0;} 38 } 39 inline void rotate(int x) 40 { 41 int y=t[x].fa; 42 int z=t[y].fa; 43 int k=(t[y].ch[1]==x); 44 t[z].ch[t[z].ch[1]==y]=x; 45 t[x].fa=z; 46 t[y].ch[k]=t[x].ch[k^1]; 47 t[t[x].ch[k^1]].fa=y; 48 t[x].ch[k^1]=y; 49 t[y].fa=x; 50 pushup(y);pushup(x); 51 } 52 inline void splay(int x,int tag) 53 { 54 while(t[x].fa!=tag){ 55 int y=t[x].fa; 56 int z=t[y].fa; 57 if(z!=tag) 58 (t[y].ch[1]==x)^(t[z].ch[1]==y)? 59 rotate(x):rotate(y); 60 rotate(x);} 61 if(tag==0)root=x; 62 } 63 inline void insert(int x) 64 { 65 int now=root,fa=0; 66 while(now) 67 fa=now,now=t[now].ch[x>t[now].val]; 68 now=++tot; 69 if(fa)t[fa].ch[x>t[fa].val]=now; 70 t[now].add(x,fa); 71 splay(now,0); 72 } 73 inline int find(int x) 74 { 75 int now=root; 76 while(555){ 77 pushdown(now); 78 if(t[t[now].ch[0]].size>=x)now=t[now].ch[0]; 79 else if(t[t[now].ch[0]].size+1==x)return now; 80 else x-=(t[t[now].ch[0]].size+1),now=t[now].ch[1]; 81 } 82 } 83 inline int getmax(int x) 84 { 85 pushdown(x); 86 while(t[x].ch[1]){ 87 x=t[x].ch[1]; 88 pushdown(x);} 89 return x; 90 } 91 inline void merge(int x,int y) 92 { 93 t[x].ch[1]=y; 94 t[y].fa=x; 95 } 96 inline void flip(int l,int r) 97 { 98 l=find(l),r=find(r+2); 99 splay(l,0);splay(r,l); 100 t[t[t[root].ch[1]].ch[0]].mark^=1; 101 } 102 inline void cut(int x,int y,int z) 103 { 104 int l=find(x),r=find(y+2); 105 splay(l,0);splay(r,l); 106 //找到移动区间的左右端点的位置并调整至根节点 107 int root1=t[t[root].ch[1]].ch[0]; 108 t[t[root].ch[1]].ch[0]=0; 109 //将该区间“截”下来 110 pushup(t[root].ch[1]); 111 pushup(root); 112 //调整节点信息 113 int neo=find(z+1); 114 splay(neo,0); 115 //找到放入区间的左端点并调整至根节点 116 int root2=t[root].ch[1]; 117 //记录下当前的右端点,因为待会儿合并时会将它直接去掉 118 merge(root,root1); 119 pushup(root); 120 //将截取区间接到当前根节点的右端点 121 int maxx=getmax(root); 122 splay(maxx,0); 123 //找到已经放入的区间的右端点并将其调整至根节点 124 merge(root,root2); 125 pushup(root); 126 //将之前被截取下来的端点和根节点 127 } 128 inline void travel(int now) 129 { 130 pushdown(now); 131 if(t[now].ch[0])travel(t[now].ch[0]); 132 if(t[now].val>1&&t[now].val<n+2) 133 ans[++cnt]=t[now].val-1; 134 if(t[now].ch[1])travel(t[now].ch[1]); 135 } 136 int main() 137 { 138 while(555){ 139 n=read();m=read(); 140 if(n<0||m<0)break; 141 root=tot=0; 142 for(int i=1;i<=n+2;i++) 143 insert(i); 144 char opt[5];int x,y,z; 145 for(int i=1;i<=m;i++){ 146 scanf("%s",opt); 147 if(opt[0]==‘F‘){ 148 x=read();y=read(); 149 flip(x,y);} 150 else{ 151 x=read();y=read();z=read(); 152 cut(x,y,z);} 153 } 154 cnt=0; 155 travel(root); 156 for(int i=1;i<n;i++) 157 printf("%d ",ans[i]); 158 printf("%d\n",ans[n]); 159 } 160 return 0;
以上是关于HDU3487 Play With Chain [Splay]的主要内容,如果未能解决你的问题,请参考以下文章
hdu 3487 Play with Chain (Splay)