BZOJ4415: [Shoi2013]发牌

BZOJ4415: [Shoi2013]发牌

Description

假设一开始,荷官拿出了一副新牌,这副牌有N张不同的牌,编号依次为1到N。由于是新牌,所以牌是按照顺序排好的,从牌库顶开始,依次为1, 2,……直到N,N号牌在牌库底。为了发完所有的牌,荷官会进行N次发牌操作,在第i次发牌之前,他会连续进行R_i次销牌操作,R_i由输入给定。请问最后玩家拿到这副牌的顺序是什么样的?

举个例子,假设N = 4,则一开始的时候,牌库中牌的构成顺序为{1, 2, 3, 4}。

假设R1=2,则荷官应该连销两次牌,将1和2放入牌库底,再将3发给玩家。目前牌库中的牌顺序为{4, 1, 2}。

假设R2=0,荷官不需要销牌,直接将4发给玩家,目前牌库中的牌顺序为{1,2}。

假设R3=3,则荷官依次销去了1, 2, 1,再将2发给了玩家。目前牌库仅剩下一张牌1。

假设R4=2,荷官在重复销去两次1之后,还是将1发给了玩家,这是因为1是牌库中唯一的一张牌。

Input

第1行,一个整数N,表示牌的数量。第2行到第N + 1行,在第i + 1行,有一个整数R_i, 0≤R_i<N

Output

第1行到第N行:第i行只有一个整数,表示玩家收到的第i张牌的编号。

 

Sample Input

4
2
0
3
2

Sample Output

3
4
2
1

HINT

N<=70万


题解Here!

 

先说一点题外话:

这种题目,怎么能没有线段树的题解呢?

弄得我好方啊。。。

然而我写了个线段树,调了$2h$,发现我就是个沙茶,竟然把$s$敲成了$k$。。。

这样下去吃草药丸。。。

步入正题:

首先应该看出这是个求整个区间的第$k$大值。

这种题目$Splay,Treap$乱搞啊。。。

但是$n<=7\times 10^5$,这。。。铁定$TLE$啊。。。

然后我们想,还有什么可以求第$k$大值呢?

没错!主席树

但是这题不用主席树,因为只要求整个区间的第$k$大值,所以用个权值线段树就好辣!

假设当前的牌堆顶为$k$,现在要销牌$x$次,一共有$sum$张牌。

那么我们要发的那张牌就是第$(k+x)\mod sum$张牌。

注意:如果$(k+x)\mod sum==0$,那么要发的就是第$sum$张牌。

然后在权值线段树中把发过的那张牌删掉就好。

记得用一点常数优化之类的东西。。。

还有,我的权值线段树极度压行,还有一大堆宏定义,要仔细看哦!

附代码:

#include<iostream>
#include<algorithm>
#include<cstdio>
#define LSON rt<<1
#define RSON rt<<1|1
#define DATA(x) a[x].data
#define LSIDE(x) a[x].l
#define RSIDE(x) a[x].r
#define WIDTH(x) (RSIDE(x)-LSIDE(x)+1)
#define MAXN 1000010
using namespace std;
int n,m;
struct Segment_Tree{
	int data,l,r;
}a[MAXN<<2];
inline int read(){
	int date=0,w=1;char c=0;
	while(c<'0'||c>'9'){if(c=='-')w=-1;c=getchar();}
	while(c>='0'&&c<='9'){date=date*10+c-'0';c=getchar();}
	return date*w;
}
void buildtree(int l,int r,int rt){
	LSIDE(rt)=l;RSIDE(rt)=r;DATA(rt)=WIDTH(rt);
	if(l==r)return;
	int mid=l+r>>1;
	buildtree(l,mid,LSON);
	buildtree(mid+1,r,RSON);
}
void update(int k,int rt){
	DATA(rt)--;
	if(LSIDE(rt)==RSIDE(rt))return;
	int mid=LSIDE(rt)+RSIDE(rt)>>1;
	if(k<=mid)update(k,LSON);
	else update(k,RSON);
}
int query(int k,int rt){
	if(LSIDE(rt)==RSIDE(rt))return LSIDE(rt);
	if(k<=DATA(LSON))return query(k,LSON);
	else return query(k-DATA(LSON),RSON);
}
void work(){
	int x,s,k=1;
	while(n--){
		x=read();
		k=(k+x)%DATA(1);
		if(!k)k=DATA(1);
		s=query(k,1);
		printf("%d\n",s);
		update(s,1);
	}
}
void init(){
	n=read();
	buildtree(1,n,1);
}
int main(){
	init();
	work();
    return 0;
}

 

posted @ 2018-08-23 21:21  符拉迪沃斯托克  阅读(215)  评论(0编辑  收藏  举报
Live2D