zoukankan      html  css  js  c++  java
  • 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 imes 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
    ",s);
    		update(s,1);
    	}
    }
    void init(){
    	n=read();
    	buildtree(1,n,1);
    }
    int main(){
    	init();
    	work();
        return 0;
    }
    
  • 相关阅读:
    Java--泛型
    Java--文档注释
    Java--网络编程
    Java--序列化
    Java--多线程编程
    Java--ConcurrentHashMap原理分析
    HashMap底层实现原理/HashMap与HashTable区别/HashMap与HashSet区别
    面向接口编程详解
    面向接口编程
    base64 数据加密
  • 原文地址:https://www.cnblogs.com/Yangrui-Blog/p/9526427.html
Copyright © 2011-2022 走看看