zoukankan      html  css  js  c++  java
  • 【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;
    }
    

     

  • 相关阅读:
    155. 最小栈
    160. 相交链表
    PAT 1057 Stack
    PAT 1026 Table Tennis
    PAT 1017 Queueing at Bank
    PAT 1014 Waiting in Line
    PAT 1029 Median
    PAT 1016 Phone Bills
    PAT 1010 Radix
    PAT 1122 Hamiltonian Cycle
  • 原文地址:https://www.cnblogs.com/GXZlegend/p/7715591.html
Copyright © 2011-2022 走看看