zoukankan      html  css  js  c++  java
  • Hdu 3487 play the chain 题解(fhq_treap)

    3487: Play with Chain

    Time Limit: 10 Sec Memory Limit: 256 MB

    Description

    瑶瑶很喜欢玩项链,她有一根项链上面有很多宝石,宝石从1到n编号。
    首先,项链上的宝石的编号组成一个序列:1,2,3,...,n。
    她喜欢两种操作:
    1.CUT a b c:他会先将a至b号宝石切下来,然后接到c号宝石后面,组成一个新的项链。
    举个例子,如果n=8,那么这个项链上的宝石编号依次为:1 2 3 4 5 6 7 8;'CUT 3 5 4',首先我们把3到5号宝石切下
    项链变成了:1 2 6 7 8;然后接到4号宝石后面,此时的4号宝石为7,所以此时的项链变成了:1 2 6 7 3 4 5 8.
    2.FLIP a b:像第一个操作一样我们先将a至b号宝石切下来,然后将其旋转180°,变成与原来相反的链,在插入到项链的相 同位置中。
    举个例子,取操作1中的链:1 2 3 4 5 6 7 8,执行FLIP 2 6操作,则项链将变成:1 6 5 4 3 2 7 8.
    他想知道经过m个操作之后项链会变成怎样。

    Input

    对于每一个数据,第一行会有两个整数:(n,m(1leq n,mleq 300000)) (n)代表宝石的个数,(m)代表操作的个数。
    接下来有(m)行 有两个操作:
    CUT A B C //代表CUT操作,(1leq Aleq Bleq N, 0leq Cleq N-(B-A+1)).
    FLIP A B //代表FLIP操作,(1leq Aleq Bleq N).
    输出的结尾将会有两个负数,他们不能当做操作.

    Output

    对于每一个数据,你需要输出(n)个整数,任两个数字间用一个空格分开,代表最终得到的项链的从1到(n)的宝石的序列号。

    Sample Input

    8 2
    CUT 3 5 4
    FLIP 2 6
    -1 -1

    Sample Output

    1 4 3 7 6 2 5 8

    HINT


    题意:

    (n)个元素的序列,(m)个操作,支持剪切区间和翻转区间两种操作
    原序列为1 2 3 4 5 6 7 8
    cut操作,先将3~5号元素剪切下来
    序列变为1 2 6 7 8
    此时四号元素为7,再将剪切下来的元素放在7后面
    序列变为1 2 6 7 3 4 5 8
    flip操作,翻转2~6号元素
    得1 4 3 7 6 2 5 8


    题解

    分析题意,题目让我们维护一个序列,支持两种操作,可以考虑杨fhq_treap来写
    考虑到cut操作,其实就是先将a~b分离出来再插入到c号元素之后即可,直接split和merge即可完成此操作
    至于flip操作,分离出a~b区间,再打Lazy标记即可
    详见代码

    #include<bits/stdc++.h>
    #define F(i,j,n) for(register int i=j;i<=n;i++)
    #define INF 0x3f3f3f3f
    #define ll long long
    #define mem(i,j) memset(i,j,sizeof(i))
    using namespace std;
    int n,m,ansnum=0;
    inline int read(){
    	int datta=0;char chchc=getchar();bool okoko=0;
    	while(chchc<'0'||chchc>'9'){if(chchc=='-')okoko=1;chchc=getchar();}
    	while(chchc>='0'&&chchc<='9'){datta=datta*10+chchc-'0';chchc=getchar();}
    	return okoko?-datta:datta;
    }
    class Fhq_Treap{
    	private:
    	public:
    	int tot,son[1200010][2],key[1200010],val[1200010],sz[1200010];
    	inline void updata(int u){
    		sz[u]=sz[son[u][0]]+sz[son[u][1]]+1;
    	}
    	inline void build(int l,int r,int lst){
    		if(r<l)
    			return ;
    		if(l==r){
    			son[lst][lst<l]=l;
    			key[l]=rand();
    			val[l]=l;
    			sz[l]=1;
    			return ;
    		}
    		int mid=(l+r)>>1;
    		son[lst][lst<mid]=mid;
    		key[mid]=rand();
    		val[mid]=mid;
    		build(l,mid-1,mid);
    		build(mid+1,r,mid);
    		updata(mid);
    	}
    	inline void make_rev_tag(int u){
    		rev[u]^=1;
    		swap(son[u][0],son[u][1]);
    	}
    	inline void pushdown(int u){
    		if(rev[u]){
    			if(son[u][0])
    				make_rev_tag(son[u][0]);
    			if(son[u][1])
    				make_rev_tag(son[u][1]);
    			rev[u]=0;
    		}
    	}
    	inline pair<int,int>split(int u,int k){
    		if(!k)
    			return make_pair(0,u);
    		if(k==sz[u])
    			return make_pair(u,0);
    		pushdown(u);
    		if(k<=sz[son[u][0]]){
    			pair<int,int>res=split(son[u][0],k);
    			son[u][0]=res.second;
    			updata(u);
    			return make_pair(res.first,u);
    		}else{
    			pair<int,int>res=split(son[u][1],k-sz[son[u][0]]-1);
    			son[u][1]=res.first;
    			updata(u);
    			return make_pair(u,res.second);
    		}
    	}
    	inline int merge(int x,int y){
    		if(!x||!y)
    			return x+y;
    		pushdown(x);
    		pushdown(y);
    		if(key[x]<key[y]){
    			son[x][1]=merge(son[x][1],y);
    			updata(x);
    			return x;
    		}else{
    			son[y][0]=merge(x,son[y][0]);
    			updata(y);
    			return y;
    		}
    	}
    	int rt;
    	bool rev[1200010];
    	inline void prepare(){
    		tot=n;
    		rt=(1+n)>>1;
    		build(1,n,0);
    	}
    	inline void rever(int l,int r){
    		pair<int,int>spl1=split(rt,r);
    		pair<int,int>spl2=split(spl1.first,l-1);//分离a~b区间
    		make_rev_tag(spl2.second);//打Lazy标记
    		rt=merge(merge(spl2.first,spl2.second),spl1.second);
    	}
    	inline void print_ans(int u){
    		if(!u)
    			return ;
    		pushdown(u);
    		print_ans(son[u][0]);
    		if(ansnum==n-1)
    			printf("%d",val[u]);
    		else
    			printf("%d ",val[u]);//避免PE
    		ansnum++;
    		print_ans(son[u][1]);
    	}
    }F;
    int main(){
    	n=read();m=read();
    	while(n!=-1&&m!=-1){
    		mem(F.son,0);mem(F.key,0);mem(F.val,0);mem(F.sz,0);mem(F.rev,0);
    		F.rt=F.tot=ansnum=0;
    		F.prepare();//建初始树
    		F(i,1,m){
    			char ch=getchar();
    			while(ch!='C'&&ch!='F')
    				ch=getchar();
    			int a=read(),b=read(),c;
    			if(ch=='C'){
    				c=read();
    				pair<int,int>spl1=F.split(F.rt,b);
    				pair<int,int>spl2=F.split(spl1.first,a-1);
    				F.rt=F.merge(spl2.first,spl1.second);//上面三行分离出a~b区间
    				pair<int,int>spl3=F.split(F.rt,c);//分离c区间
    				F.rt=F.merge(F.merge(spl3.first,spl2.second),spl3.second);//重新组合
    			}else{
    				F.rever(a,b);//翻转操作
    			}
    		}
    		F.print_ans(F.rt);//按前序遍历输出答案
    		printf("
    ");
    		n=read();m=read();
    	}
    	return 0;
    }
    
    
  • 相关阅读:
    诗人就是“情场浪子”的代名词?
    微博营销,开启营销的新时代
    网店成功之道:卖家应有4种心态(实战交流)
    一枚钉子前进
    推动中国文学的发展,我义不容辞
    微博营销,再次引爆网络江湖
    微博营销,不仅仅是粉丝
    邮件群发软件版本升级公告
    如何让自己在浩瀚的网海中脱颖而出
    如何定时关机【windows/linux】
  • 原文地址:https://www.cnblogs.com/hzf29721/p/10159553.html
Copyright © 2011-2022 走看看