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
2
0
3
2
Sample Output
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;
}

浙公网安备 33010602011771号