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万

Solution

一看是splay裸题就上splay硬艹结果因为人傻常数大只有80……于是换了线段树写法

开个线段树存一下每种牌的数量0/1
在值域线段树上二分即可。
代码简单易懂

最后面贴一下我GG的splay

Code

 #include<iostream>
#include<cstdio>
#define N (700000+1000)
using namespace std; int Segt[N<<]; inline int read()
{
int x=,w=; char c=getchar();
while (!isdigit(c)&&c!='-') c=getchar();
if (c=='-') c=getchar(),w=-;
while (isdigit(c)){x=(x<<)+(x<<)+c-'';c=getchar();}
return x*w;
} void Build(int now,int l,int r)
{
if (l==r){Segt[now]=; return;}
int mid=(l+r)>>;
Build(now<<,l,mid); Build(now<<|,mid+,r);
Segt[now]=Segt[now<<]+Segt[now<<|];
} void Update(int now,int l,int r,int k)
{
Segt[now]--;
if (l==r){printf("%d\n",l); return;}
int mid=(l+r)>>;
if (k<=Segt[now<<]) Update(now<<,l,mid,k);
else Update(now<<|,mid+,r,k-Segt[now<<]);
} int main()
{
int n,x,p=;
n=read();
Build(,,n);
for (int i=; i<=n; ++i)
{
x=read();
p=(p+x)%(n-i+);
Update(,,n,p+);
}
}
 #include<iostream>
#include<cstdio>
#define N (700000+1000)
using namespace std; int n,x,Root,Father[N],Son[N][],Size[N]; void Update(int x){Size[x]=+Size[Son[x][]]+Size[Son[x][]];}
int Get(int x){return Son[Father[x]][]==x;} inline int read()
{
int x=,w=;
char c=getchar();
while (!isdigit(c)&&c!='-') c=getchar();
if (c=='-') c=getchar(),w=-;
while (isdigit(c)){x=(x<<)+(x<<)+c-'';c=getchar();}
return x*w;
} void Build(int fa,int l,int r)
{
if (l>r) return;
if (l==r) Size[l]=;
int mid=(l+r)>>;
Build(mid,l,mid-);
Build(mid,mid+,r);
Father[mid]=fa; Son[fa][mid>fa]=mid;
Update(mid);
} void Rotate(int x)
{
int wh=Get(x);
int fa=Father[x],fafa=Father[fa];
if (fafa) Son[fafa][Son[fafa][]==fa]=x;
Father[fa]=x; Son[fa][wh]=Son[x][wh^];
Father[x]=fafa; Son[x][wh^]=fa;
if (Son[fa][wh]) Father[Son[fa][wh]]=fa;
Update(fa); Update(x);
} void Splay(int x,int tar)
{
for (int fa; (fa=Father[x])!=tar; Rotate(x))
if (Father[fa]!=tar)
Rotate(Get(fa)==Get(x)?fa:x);
if (!tar) Root=x;
} int Findkth(int x)
{
int now=Root;
while ()
if (Size[Son[now][]]>=x) now=Son[now][];
else
{
x-=Size[Son[now][]];
if (x==){/*Splay(now,0);*/ return now;}
x--; now=Son[now][];
}
} int Split(int l,int r)
{
int x=Findkth(l);
int y=Findkth(r+);
Splay(x,); Splay(y,x);
return Son[y][];
} int main()
{
n=read();
Build(,,n+);
Root=(n+)>>;
for (int i=; i<=n; ++i)
{
x=read();
x%=n-i+;
if (x)
{
int now=Split(,x);
Son[Father[now]][Son[Father[now]][]==now]=;
Father[now]=;
int fa=Split(n-i+-x,n-i+-x);
Son[fa][]=now; Father[now]=fa;
Splay(now,);
}
int now=Split(,); printf("%d\n",now-);
Son[Father[now]][]=;
Father[now]=; Update(Son[Root][]);
}
}

BZOJ4415:[SHOI2013]发牌(线段树)的更多相关文章

  1. BZOJ4415 SHOI2013发牌(线段树)

    似乎是noip2017d2t3的一个部分分.用splay的话当然非常裸,但说不定会被卡常.可以发现序列中数的(环上)相对位置是不变的,考虑造一棵权值线段树维护权值区间内还有多少个数留在序列中,每次在线 ...

  2. BZOJ4415: [Shoi2013]发牌 树状数组+二分

    Description 假设一开始,荷官拿出了一副新牌,这副牌有N张不同的牌,编号依次为1到N.由于是新牌,所以牌是按照顺序排好的,从牌库顶开始,依次为1, 2,……直到N,N号牌在牌库底.为了发完所 ...

  3. BZOJ4415: [Shoi2013]发牌

    显然可以线段树或树状数组上二分. 然而直接写splay在bzoj上并不会T. 然而发这题的目的只是因为我又忘了return了啊啊啊啊(TдT) 内心十分崩溃.关键是在本地还能过. #include&l ...

  4. bzoj 4415: [Shoi2013]发牌

    4415: [Shoi2013]发牌 Time Limit: 10 Sec  Memory Limit: 256 MBSubmit: 173  Solved: 124[Submit][Status][ ...

  5. [SHOI2013]发牌 解题报告

    [SHOI2013]发牌 题意 对一个\(1\sim n(n\le 7\times 10^5)\)的环,指标最开始在\(1\),每次删去顺时针往后第\(d_i\)个元素,指标移到下一个位置.要求输出每 ...

  6. P3988 [SHOI2013]发牌

    题目 P3988 [SHOI2013]发牌 做法 我们切牌时的状态: 手玩几次后我们发现切\(K\)次牌就是求堆顶一下的\(K+1\)大值,套上主席树就好了 My complete code #inc ...

  7. bzoj3932--可持久化线段树

    题目大意: 最近实验室正在为其管理的超级计算机编制一套任务管理系统,而你被安排完成其中的查询部分.超级计算机中的 任务用三元组(Si,Ei,Pi)描述,(Si,Ei,Pi)表示任务从第Si秒开始,在第 ...

  8. codevs 1082 线段树练习 3(区间维护)

    codevs 1082 线段树练习 3  时间限制: 3 s  空间限制: 128000 KB  题目等级 : 大师 Master 题目描述 Description 给你N个数,有两种操作: 1:给区 ...

  9. codevs 1576 最长上升子序列的线段树优化

    题目:codevs 1576 最长严格上升子序列 链接:http://codevs.cn/problem/1576/ 优化的地方是 1到i-1 中最大的 f[j]值,并且A[j]<A[i] .根 ...

随机推荐

  1. PIE SDK波段运算

    1.算法功能简介 波段运算(Band Math)工具能够方便的执行图像中的各个波段的加减乘除.三角函数.指数.对数等数学函数计算,也可以使用IDL编写的函数. 由于每个用户都有独特的需求,利用此工具用 ...

  2. 线程同步(windows平台):信号量

    一:介绍 信号量也是系统核心对象,它允许多个线程同一时刻访问同一资源,但需限制同一时刻访问资源的最大线程数目. 信号量遵循规则:1.当前资源计数大于0,信号量有效.2.当前资源计数等于0,信号量无效. ...

  3. mongodb常用语句(集合操作)

    mongodb常用语句(集合操作) 查看集合帮助 db.songs.help(); 查看集合总数据量 db.songs.count(); 查看表空间大小 db.songs.dataSize(); 查看 ...

  4. JQuery脚本-通过禁用按钮防止表单重复提交

    <script type="text/javascript"> /* jquer 脚本,避免重复提交 隐藏点击的submit,后在他之后插入同名button伪装成被隐藏 ...

  5. JVM 类加载全过程

    类加载机制 - JVM把class文件加载到内存中 并对数据进行 校验,解析,初始化,最终形成JVM可以直接使用的java类型的过程 详细过程  加载→ 验证→ 准备→ 解析 → 初始化→ 使用 → ...

  6. SQLAlchemy基本操作和常用技巧

    点击打开链接 Python的ORM框架SQLAlchemy基本操作和常用技巧,包含大量实例,非常好的一个学习SQLAlchemy的教程,需要的朋友可以参考下 python编程语言下的一款开源软件.提供 ...

  7. 虚拟机中Linux设置当前ip

    1.查看当前IP,查看网卡信息 ifconfig 2.设置临时IP ifconfig eth0 192.168.1.163 netmask 255.255.255.0 eth0表示第一块网卡 设置完之 ...

  8. 【学习笔记】HTML基础:使用html制作网页

    一.初识HTML 1.什么是HTML? Hyper Text Markup Language(超文本标记语言) 扩展XML:Extendsible  Markup Language(可扩展性标记语言) ...

  9. python的if语句

    1.条件测试 (1)概念: 每条if语句的核心都是一个值为True或False的表达式,这种表达式被称为条件测试.Python 根据条件测试的值为True还是False来决定是否执行if语句中的代码. ...

  10. Android-自定义View实现ImageView播放gif

    http://blog.csdn.net/guolin_blog/article/details/11100315 总体思路是这样的 PowerImageView类继承ImageView类 给Powe ...