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万
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]发牌(线段树)的更多相关文章
- BZOJ4415 SHOI2013发牌(线段树)
似乎是noip2017d2t3的一个部分分.用splay的话当然非常裸,但说不定会被卡常.可以发现序列中数的(环上)相对位置是不变的,考虑造一棵权值线段树维护权值区间内还有多少个数留在序列中,每次在线 ...
- BZOJ4415: [Shoi2013]发牌 树状数组+二分
Description 假设一开始,荷官拿出了一副新牌,这副牌有N张不同的牌,编号依次为1到N.由于是新牌,所以牌是按照顺序排好的,从牌库顶开始,依次为1, 2,……直到N,N号牌在牌库底.为了发完所 ...
- BZOJ4415: [Shoi2013]发牌
显然可以线段树或树状数组上二分. 然而直接写splay在bzoj上并不会T. 然而发这题的目的只是因为我又忘了return了啊啊啊啊(TдT) 内心十分崩溃.关键是在本地还能过. #include&l ...
- bzoj 4415: [Shoi2013]发牌
4415: [Shoi2013]发牌 Time Limit: 10 Sec Memory Limit: 256 MBSubmit: 173 Solved: 124[Submit][Status][ ...
- [SHOI2013]发牌 解题报告
[SHOI2013]发牌 题意 对一个\(1\sim n(n\le 7\times 10^5)\)的环,指标最开始在\(1\),每次删去顺时针往后第\(d_i\)个元素,指标移到下一个位置.要求输出每 ...
- P3988 [SHOI2013]发牌
题目 P3988 [SHOI2013]发牌 做法 我们切牌时的状态: 手玩几次后我们发现切\(K\)次牌就是求堆顶一下的\(K+1\)大值,套上主席树就好了 My complete code #inc ...
- bzoj3932--可持久化线段树
题目大意: 最近实验室正在为其管理的超级计算机编制一套任务管理系统,而你被安排完成其中的查询部分.超级计算机中的 任务用三元组(Si,Ei,Pi)描述,(Si,Ei,Pi)表示任务从第Si秒开始,在第 ...
- codevs 1082 线段树练习 3(区间维护)
codevs 1082 线段树练习 3 时间限制: 3 s 空间限制: 128000 KB 题目等级 : 大师 Master 题目描述 Description 给你N个数,有两种操作: 1:给区 ...
- codevs 1576 最长上升子序列的线段树优化
题目:codevs 1576 最长严格上升子序列 链接:http://codevs.cn/problem/1576/ 优化的地方是 1到i-1 中最大的 f[j]值,并且A[j]<A[i] .根 ...
随机推荐
- TT 安装 之 LINUX
# useradd ttadmin -- 创建用户 # groupadd ttadmin -- 创建用户组 # mkdir /etc/TimesTen -- 创建目录 # chgrp -R ttadm ...
- linux 7.0+救援模式
输入“e”进入GRUB页面! 定位到ro 然后修改ro为rw,并添加如下红框内的命令行! 使用下面的提示使用“Ctrl-x”start!!! 进入系统后,其实只是进入了一个安全模式下的内存系统,并不是 ...
- 数据库~大叔通过脚本生成poco实体
今天在做开发时,需要把表映射成实体,又没有EF这种工具,就从网上下了一个工具,但使用时觉得太重了,所以就自己写了一个,基于mysql的. 功能:输入表名,得到这个表的poco实体 SELECT COL ...
- innosetup区分正常状态和静默安装状态(通过传递的参数)
命令行运行程序,如: myprogram.exe /abc /bcd 如果我们想获取其中的参数,“/abc”.“/bcd” 1. 直接使用innosetup自带的方法, GetCmdTail() ...
- sqlserver2008 调试存储过程
1.创建所需要调试的存储过程,并执行一下,也就是保存好 ,我要演示的存储过程名是 “usp_Passport_GetNewDepositary” 2.找到存储过程,右键“执行存储过程”,会弹出如下的界 ...
- Java读写锁
Java读写锁,ReadWriteLock.java接口, RentrantReadWriteLock.java实现.通过读写锁,可以实现读-读线程并发,读-写,写-读线程互斥进行.以前面试遇到一个问 ...
- Socket编程指南及示例程序(转)
1 前言 在一些常用的编程技术中,Socket网络编程可以说是最简单的一种.而且Socket编程需要的基础知识很少,适合初学者学习网络编程.目前支持网络传输的技术.语言和工具繁多,但是 ...
- TensorFlow入门:mac 安装 TensorFlow
开发环境: mac os 10.12.5 Python 2.7.10 GCC 4.2.1 mac默认是不带pip的,安装pip. sudo easy_install pip 1.安装virtualen ...
- Spring注解之Controller中获取请求参数及验证使用
1.处理request的uri部分的参数:@PathVariable. 2.处理request header部分的参数:@RequestHeader,@CookieValue@RequestHeade ...
- Vue element-ui:滚动条 分页 禁用选项
1.滚动条设置: <el-scrollbar style="height:100%;">.......</el-scrollbar> 默认会同时出现水平和垂 ...