【bzoj5063】旅游 Splay

题目描述

给定一个1...n的序列,有m次操作,每次操作有6步:
1、从序列开头(左端)取出A个数(此时序列剩下n-A个数)
2、从序列开头取出B个数
3、将第1步取出的A个数按原顺序放回序列开头
4、从序列开头取出C个数
5、将第2步取出的B个数逆序放回序列开头
6、将第4步取出的C个数按原顺序放回序列开头
你需要求出最终序列。

输入

第一行两个数n,m。接下来m行,每行三个数A,B,C。
n,m<=100000

输出

输出一行n个数表示最终序列。

样例输入

10 2
6 2 2
5 3 6

样例输出

1 2 8 7 3 9 6 5 4 10


题解

Splay裸题

题目中操作显然可以直接使用Splay解决

然而本题卡常,直接模拟每次的6个步骤会T得很惨。。。

考虑一下操作的实质:把第$A+1$个到第$A+B$个拿出来,再翻转一下放回到序列的第C个的后面。这个过程可以直接两次操作完成。常数减到直接模拟的1/3。

注意最后输出时不能对于每一个都find一遍(这样Splay的均摊分析不成立,除非find后splay到根),最好的方法是dfs一遍Splay Tree,此时不要忘记pushdown。

另外亲测数组版比结构体版慢了1倍左右= =

#include <cstdio>
#include <cctype>
#include <algorithm>
using namespace std;
#define N 100010
struct data
{
	int fa , c[2] , si , rev;
}a[N];
int root , ans[N] , tot;
inline void rever(int x)
{
	swap(a[x].c[0] , a[x].c[1]) , a[x].rev ^= 1;
}
inline void pushup(int x)
{
	a[x].si = a[a[x].c[0]].si + a[a[x].c[1]].si + 1;
}
inline void pushdown(int x)
{
	if(a[x].rev) rever(a[x].c[0]) , rever(a[x].c[1]) , a[x].rev = 0;
}
inline void rotate(int &k , int x)
{
	int y = a[x].fa , z = a[y].fa , l = (a[y].c[1] == x) , r = l ^ 1;
	if(y == k) k = x;
	else a[z].c[a[z].c[1] == y] = x;
	a[x].fa = z , a[y].fa = x , a[a[x].c[r]].fa = y , a[y].c[l] = a[x].c[r] , a[x].c[r] = y;
	pushup(y) , pushup(x);
}
inline void splay(int &k , int x)
{
	int y , z;
	while(x != k)
	{
		y = a[x].fa , z = a[y].fa;
		if(y != k)
		{
			if((a[y].c[0] == x) ^ (a[z].c[0] == y)) rotate(k , x);
			else rotate(k , y);
		}
		rotate(k , x);
	}
}
int find(int k , int x)
{
	pushdown(k);
	if(x <= a[a[k].c[0]].si) return find(a[k].c[0] , x);
	else if(x > a[a[k].c[0]].si + 1) return find(a[k].c[1] , x - a[a[k].c[0]].si - 1);
	else return k;
}
inline int split(int l , int r)
{
	int x = find(root , l) , y = find(root , r + 2);
	splay(root , x) , splay(a[root].c[1] , y);
	return a[a[root].c[1]].c[0];
}
int build(int l , int r)
{
	if(l > r) return 0;
	int mid = (l + r) >> 1;
	a[mid].c[0] = build(l , mid - 1) , a[a[mid].c[0]].fa = mid;
	a[mid].c[1] = build(mid + 1 , r) , a[a[mid].c[1]].fa = mid;
	pushup(mid);
	return mid;
}
void dfs(int x)
{
	if(!x) return;
	pushdown(x) , dfs(a[x].c[0]) , ans[++tot] = x , dfs(a[x].c[1]);
}
inline char nc()
{
	static char buf[100000] , *p1 , *p2;
	return p1 == p2 && (p2 = (p1 = buf) + fread(buf , 1 , 100000 , stdin) , p1 == p2) ? EOF : *p1 ++ ;
}
inline int read()
{
	int ret = 0; char ch = nc();
	while(!isdigit(ch)) ch = nc();
	while(isdigit(ch)) ret = ((ret + (ret << 2)) << 1) + (ch ^ '0') , ch = nc();
	return ret;
}
int main()
{
	int n = read() , m = read() , i , A , B , C , x;
	root = build(1 , n + 2);
	for(i = 1 ; i <= m ; i ++ )
	{
		A = read() , B = read() , C = read();
		x = split(A + 1 , A + B) , a[a[x].fa].c[0] = 0 , pushup(a[x].fa) , pushup(root) , rever(x);
		split(C + 1 , C) , a[x].fa = a[root].c[1] , a[a[x].fa].c[0] = x , pushup(a[x].fa) , pushup(root);
	}
	dfs(root);
	for(i = 2 ; i <= n + 1 ; i ++ ) printf("%d " , ans[i] - 1);
	return 0;
}

 

原文地址:https://www.cnblogs.com/GXZlegend/p/7715591.html