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; }