P3988 [SHOI2013] 发牌
P3988 [SHOI2013] 发牌
题目描述
在一些扑克游戏里,如德州扑克,发牌是有讲究的。一般称呼专业的发牌手为荷官。荷官在发牌前,先要销牌(burn card)。所谓销牌,就是把当前在牌库顶的那一张牌移动到牌库底,它用来防止玩家猜牌而影响游戏。
假设一开始,荷官拿出了一副新牌,这副牌有
数据规模与约定
对于
说句闲话:
年底平衡树大甩卖,比模板还简单的平衡树紫题仅需40行,走过路过不要错过!
Solution:
言归正转,我们只需要搞清楚这题的洗牌方式就能愉快的把这题A掉。
以初始序列为例,假设我们要进行
第0次:
第1次:
第2次:
第
所以“连续进行
但是要注意的是,由于我们牌的序列是动态的,也就是说,我上述所有的标号是其实当前的牌堆序列的下标,而不是最初的标号。所以我并不认为线段树好写,所以我选了FHQ。
Code:
#include<bits/stdc++.h> const int N=7e5+5; using namespace std; int n,m,cnt,rt; struct Tree{ int ls,rs,val,siz,rev,pri; }t[N]; inline int rd(){return rand()*rand()+17;} inline int Node(int val){t[++cnt]={0,0,val,1,0,rd()};return cnt;} inline void pushup(int x){t[x].siz=t[t[x].ls].siz+t[t[x].rs].siz+1;} inline void splite(int x,int &a,int &b,int k) { if(!x){a=b=0;return;}int tmp=t[t[x].ls].siz+1; if(k>=tmp){a=x;splite(t[x].rs,t[x].rs,b,k-tmp);} else {b=x;splite(t[x].ls,a,t[x].ls,k);} pushup(x); } int merge(int x,int y) { if(!x||!y)return x|y; if(t[x].pri<t[y].pri){t[x].rs=merge(t[x].rs,y);pushup(x);return x;} else {t[y].ls=merge(x,t[y].ls);pushup(y);return y;} } void work() { cin>>n; for(int i=1;i<=n;i++){rt=merge(rt,Node(i));} for(int i=1,x,a,b,c;i<=n;i++) { scanf("%d",&x);x=x%t[rt].siz+1; splite(rt,a,b,x-1);splite(b,b,c,1); printf("%d\n",t[b].val); rt=merge(c,a); } } int main() { work(); return 0; }