Write a program to transform the permutation 1, 2, 3,..., n according to m instructions. Each instruction(a, b) means to take out the subsequence from the a-th to the b-th element, reverse it, then append it to the end.
Input
There is only one case for this problem. The first line contains two integers n and m ( 1n, m100, 000). Each of the next m lines contains an instruction consisting of two integers a and b ( 1abn).
Output
Print n lines, one for each integer, the final permutation.
Explanation of the sample below
Instruction (2,5): Take out the subsequence {2,3,4,5}, reverse it to {5,4,3,2}, append it to the remaining permutation {1,6,7,8,9,10}
Instruction (4,8): The subsequence from the 4-th to the 8-th element of {1,6,7,8,9,10,5,4,3,2} is {8,9,10,5,4}. Take it out, reverse it, and you'll get the sample output.
Warning: Don't use cin, cout for this problem, use faster i/o methods e.g scanf, printf.
Sample Input
10 2 2 5 4 8
Sample Output
1 6 7 3 2 4 5 10 9 8
转载请注明出处:http://blog.csdn.net/scut_pein/article/details/19935423
题意:给出排列1到n,每条指令(a,,b)表示取出第a到第b个元素,翻转后添加到排列的尾部。
思路:用两个辅助结点将1到n夹在root 和 ch[root][1] 之间。
比如翻转l,r,只需要将l旋转为根,r+2旋转为根的儿子。那么ch[ch[root][1]][0] 就是 l + 1 到 r + 1。因为前面有一个辅助结点,所以这个区间才是要翻转的。
删除只需要将最后一个结点旋转为根,其后面只有一个辅助结点。那么ch[root][1] 就是辅助结点。
将删除区间放在ch[ch[root][1]][0] 即可。注意pre[]数组得更新。。。查错半天。。。
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
#define maxn 100080
#define Key_value ch[ch[root][1]][0]
int n,m;
struct SplayTree
{
int pre[maxn],key[maxn],ch[maxn][2],size[maxn],flip[maxn],root,cnt,flag;
void Treaval(int x)
{
if(x)
{
PushDown(x);
Treaval(ch[x][0]);
printf("结点%2d:左儿子 %2d 右儿子 %2d 父结点 %2d size = %2d,key = %2d \n",x,ch[x][0],ch[x][1],pre[x],size[x],key[x]);
Treaval(ch[x][1]);
}
}
void debug()
{
printf("根节点:%d\n",root);
Treaval(root);
}
void init()
{
flag = 0;
cnt = root = 0;
ch[0][0] = ch[0][1] = pre[0] = flip[0] = size[0] = 0;
NewNode(root,0,0);
NewNode(ch[root][1],0,root);
PushUp(root);
Buildtree(Key_value,1,n,ch[root][1]);
PushUp(ch[root][1]);
PushUp(root);
}
void NewNode(int & r,int k,int father)
{
r = ++cnt;
ch[r][0] = ch[r][1] = 0;
pre[r] = father;
key[r] = k;
size[r] = 1;
flip[r] = 0;
}
void Update_Rev(int r)
{
if(!r) return;
swap(ch[r][0],ch[r][1]);
flip[r] ^= 1;
}
void PushUp(int x)
{
size[x] = size[ch[x][0]] + size[ch[x][1]] + 1;
}
void PushDown(int x)
{
int l = ch[x][0],r = ch[x][1];
if(flip[x])
{
Update_Rev(l);
Update_Rev(r);
flip[x] = 0;
}
}
void Buildtree(int & r,int L,int R,int father)
{
if(L > R) return;
int mid = (L + R) >> 1;
NewNode(r,mid,father);
Buildtree(ch[r][0],L,mid-1,r);
Buildtree(ch[r][1],mid+1,R,r);
PushUp(r);
}
void Rotate(int x,int kind)
{
int y = pre[x];
PushDown(y);
PushDown(x);
ch[y][!kind] = ch[x][kind];
pre[ch[x][kind]] = y;
if(pre[y])
ch[pre[y]][ch[pre[y]][1] == y] = x;
pre[x] = pre[y];
ch[x][kind] = y;
pre[y] = x;
PushUp(y);
}
void Splay(int r,int goal)
{
PushDown(r);
while(pre[r] != goal)
{
if(pre[pre[r]] == goal)
Rotate(r,ch[pre[r]][0] == r);
else
{
int y = pre[r];
int kind = (ch[pre[y]][0] == y);
if(ch[y][kind] == r)
{
Rotate(r,!kind);
Rotate(r,kind);
}
else
{
Rotate(y,kind);
Rotate(r,kind);
}
}
}
PushUp(r);
if(goal == 0) root = r;
}
int Get_Kth(int r,int k)
{
PushDown(r);
int t = size[ch[r][0]] + 1;
if(t == k)
return r;
if(t > k)
return Get_Kth(ch[r][0],k);
else return Get_Kth(ch[r][1],k-t);
}
int Get_Min(int r)
{
PushDown(r);
while(ch[r][0])
{
r = ch[r][0];
PushDown(r);
}
return r;
}
int Get_Max(int r)
{
PushDown(r);
while(ch[r][1])
{
r = ch[r][1];
PushDown(r);
}
return r;
}
void Reversal(int l,int r)
{
int x = Get_Kth(root,l);
Splay(x,0);
int y = Get_Kth(root,r+2);
Splay(y,root);
Update_Rev(Key_value);
//printf("旋转到key_value为操作区间时:\n");
//debug();
int tmp = Key_value;
Key_value = 0;//这样就删除了这段区间
PushUp(ch[root][1]);
PushUp(root);//更新删除
//接下来要插入末尾。
//printf("删除操作区间:\n");
//debug();
int len = r - l + 1;
int xx = Get_Kth(root,n-len+1);
Splay(xx,0);
//int yy = Get_Kth(root,n-len+2);
//Splay(yy,root);
Key_value = tmp;
pre[Key_value] = ch[root][1];
PushUp(ch[root][1]);
PushUp(root);
//printf("插入尾部后:\n");
//debug();
}
void Print(int r)
{
PushDown(r);
if(ch[r][0])
Print(ch[r][0]);
if(key[r] != 0)
{
if(!flag)
printf("%d",key[r]);
else printf("\n%d",key[r]);
flag = true;
}
if(ch[r][1])
Print(ch[r][1]);
}
void solve()
{
init();
while(m--)
{
int l,r;
scanf("%d%d",&l,&r);
Reversal(l,r);
//printf("第一次操作后:\n");
//debug();
}
Print(root);
printf("\n");
}
}spt;
int main()
{
while(scanf("%d%d",&n,&m)==2)
{
spt.solve();
}
return 0;
}