hdu3436 splaytree树模拟队列+离散化缩点
数据较大,需要先把每个top不会操作到的段缩成一个点,记录其开始和结束的位置,和top能操作到的点一起建立一颗伸展树模拟
然后就是普通的队列模拟操作
/*
不会被top操作到的区间就缩点
通过splay tree模拟出序列,初始序列的第i个缩点对应的树结点也是i
操作top a:找到结点a,将其移到最左边
query a:结点a的左边有多少人
rank a:第a个结点是第几个结点
*/
#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#define maxn 100005
#define L ch[r][0]
#define R ch[r][1]
using namespace std; int pre[maxn],ch[maxn][],size[maxn],num[maxn],root,tot;
int s[maxn],e[maxn],cnt;
void debug();
inline void newnode(int &r,int fa,int k){
r=k;
ch[r][]=ch[r][]=;
pre[r]=fa;
size[r]=num[r]=e[k]-s[k]+;
}
inline void pushup(int r){
size[r]=size[L]+size[R]+num[r];
}
void build(int &x,int l,int r,int fa){
if(l>r) return;
int mid=l+r>>;
newnode(x,fa,mid);
build(ch[x][],l,mid-,x);
build(ch[x][],mid+,r,x);
pushup(x);
}
void init(int n){
root=tot=;
size[root]=pre[root]=ch[root][]=ch[root][]=;
build(root,,n,);
}
void Rotate(int x,int kind)
{
int y = pre[x];
//pushdown(y);
//pushdown(x);//先把y的标记下传,在把x的标记下传
ch[y][!kind] = ch[x][kind];
pre[ch[x][kind]] = y;
if(pre[y])
ch[pre[y]][ch[pre[y]][]==y] = x;
pre[x] = pre[y];
ch[x][kind] = y;
pre[y] = x;
pushup(y);
}
//Splay调整,将r结点调整到goal下面
void splay(int r,int goal)
{
//push_down(r);
while(pre[r] != goal)
{
if(pre[pre[r]] == goal)
Rotate(r,ch[pre[r]][]==r);
else
{
int y = pre[r];
int kind = ch[pre[y]][]==y;
if(ch[y][kind] == r)
{
Rotate(r,!kind);
Rotate(r,kind);
}
else
{
Rotate(y,kind);
Rotate(r,kind);
}
}
}
pushup(r);
if(goal == ) root = r;
}
int getmin(int r){while(L) r=L;return r;}
void del(){
int t=root;
if(ch[root][]){
root=ch[root][];
splay(getmin(root),);
ch[root][]=ch[t][];
if(ch[root][]) pre[ch[root][]]=root;
}
else root=ch[root][];
pre[root]=;
pushup(root);
}
int Bin(int x){//二分查找x属于那一段
int l=,r=cnt;
while(l<=r){
int mid=l+r>>;
if(s[mid]<=x && e[mid]>=x) return mid;
if(x<s[mid]) r=mid-;
else l=mid+;
}
return -;
}void Treavel(int x)
{
if(x)
{
Treavel(ch[x][]);
printf("结点:%2d: 左儿子 %2d 右儿子 %2d 父结点 %2d size = %2d num = %2d s = %2d e = %2d\n",x,ch[x][],ch[x][],pre[x],size[x],num[x],s[x],e[x]);
Treavel(ch[x][]);
}
}
void debug()
{
printf("root:%d\n",root);
Treavel(root);
}
void top(int x){//把结点r移到最左边
int r=Bin(x);
splay(r,);
del(); ch[r][]=;
ch[r][]=root;
pre[root]=r;
root=r;
pre[root]=;
pushup(root);
//debug();
}
int query(int x){//结点x左边有多少结点
int r=Bin(x);
splay(r,);
return size[ch[root][]]+x-s[r]+;
}
int rankk(int r,int k){//排在第k位的结点
int t=size[ch[r][]];
if(k<=t) return rankk(ch[r][],k);
else if(k<=t+num[r]) return s[r]+k-t-;
else return rankk(ch[r][],k-t-num[r]);
} char op[maxn][];
int qnum[maxn],p[maxn]; int main(){
int n,q,T;
scanf("%d",&T);
for(int tt=;tt<=T;tt++){
scanf("%d%d",&n,&q);
int t=;
for(int i=;i<q;i++){
scanf("%s%d",op[i],&qnum[i]);
if(op[i][]=='T')
p[t++]=qnum[i];
}
p[t++]=;
p[t++]=n;
sort(p,p+t);
t=unique(p,p+t)-p;
cnt=;
for(int i=;i<t;i++){
if(i> && p[i]-p[i-]>){
cnt++;
s[cnt]=p[i-]+;
e[cnt]=p[i]-;
}
cnt++;
s[cnt]=p[i];e[cnt]=p[i];
}
init(cnt);
// debug();
printf("Case %d:\n",tt);
for(int i=;i<q;i++){
// debug();
if(op[i][]=='T') top(qnum[i]);
else if(op[i][]=='Q') printf("%d\n",query(qnum[i]));
else printf("%d\n",rankk(root,qnum[i]));
// debug();
}
}
return ;
}
hdu3436 splaytree树模拟队列+离散化缩点的更多相关文章
- Splay-Tree总结一:模拟队列
伸展树是一种强大的数据结构,由于其特性,可以很好地模拟队列的插队等操作,而线段树解决这类问题通常需要转化一下,比较伤脑筋 而用伸展树的解决方法就是先建好一颗节点数等于队列长度的树,每个队列元素在队列中 ...
- 【BZOJ-2892&1171】强袭作战&大sz的游戏 权值线段树+单调队列+标记永久化+DP
2892: 强袭作战 Time Limit: 50 Sec Memory Limit: 512 MBSubmit: 45 Solved: 30[Submit][Status][Discuss] D ...
- poj3984迷宫问题 广搜+最短路径+模拟队列
转自:http://blog.csdn.net/no_retreats/article/details/8146585 定义一个二维数组: int maze[5][5] = { 0, 1, 0, ...
- POJ-2528 Mayor's posters (线段树区间更新+离散化)
题目分析:线段树区间更新+离散化 代码如下: # include<iostream> # include<cstdio> # include<queue> # in ...
- 5. redis管道, 发布订阅, 模拟队列
一. 发布订阅 #订阅scribe 127.0.0.1:6379> SUBSCRIBE "channel_1" Reading messages... (press Ctrl ...
- uva 12100 Printer Queue 优先级队列模拟题 数组模拟队列
题目很简单,给一个队列以及文件的位置,然后一个一个检查,如果第一个是优先级最高的就打印,否则放到队列后面,求所要打印的文件打印需要花费多长时间. 这里我用数组模拟队列实现,考虑到最糟糕的情况,必须把数 ...
- Java集合框架之LinkedList-----用LinkedList模拟队列和堆栈
LinkedList的特有方法: (一)添加方法 addFisrt(E e):将指定元素插入此列表的开头.//参数e可以理解成Object对象,因为列表可以接收任何类型的对象,所以e就是Object对 ...
- 3-08. 栈模拟队列(25)(ZJU_PAT 模拟)
主题链接:http://pat.zju.edu.cn/contests/ds/3-08 设已知有两个堆栈S1和S2,请用这两个堆栈模拟出一个队列Q. 所谓用堆栈模拟队列,实际上就是通过调用堆栈的下列操 ...
- hdu_5818_Joint Stacks(线段树模拟)
题目链接:hdu_5818_Joint Stacks 题意: 给你两个栈,多了个合并操作,然后让你模拟 题解: 很容易想到O(1)的单个栈操作,O(n)的合并操作,这样肯定超时,所以我们要将时间复杂度 ...
随机推荐
- yolo3的改变
转自:https://zhuanlan.zhihu.com/p/35394369 YOLOv3的前世今生 2013年,R-CNN横空出世,目标检测DL世代大幕拉开. 各路豪杰快速迭代,陆续有了SPP, ...
- Scala进阶之路-进程控制之执行shell脚本
Scala进阶之路-进程控制之执行shell脚本 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 废话不多说,我这里直接放一个案例. /* @author :yinzhengjie ...
- 数据结构(六)查找---平衡二叉树(ASL)
前提 我们之前的二叉排序树的插入(构建)是按照我们输入的数据来进行的,若是我们的数据分布不同,那么就会构造不同的二叉树 { , , , , , , , , , } { , , , , , , , , ...
- bzoj千题计划307:bzoj5248: [2018多省省队联测]一双木棋
https://www.lydsy.com/JudgeOnline/problem.php?id=5248 先手希望先手得分减后手得分最大,后手希望先手得分减后手得分最小 棋盘的局面一定是阶梯状,且从 ...
- 通用Excel文件导出工具类
1:Excel格式 2:ExcelUtil.java import java.io.ByteArrayOutputStream; import java.io.IOException; import ...
- linux僵尸进程产生的原因以及如何避免产生僵尸进程
给进程设置僵尸状态的目的是维护子进程的信息,以便父进程在以后某个时间获取.这些信息包括子进程的进程ID.终止状态以及资源利用信息(CPU时间,内存使用量等等).如果一个进程终止,而该进程有子进程处于僵 ...
- 3 快速创建SpringBoot项目
一.Intellij IDEA 创建Spring Boot项目 1.创建工程 2.选择Spring Initializr 3.设置Maven版本管理参数 4.选择引用模块 5.命名工程名 6.选 ...
- nmap学习之相关参数列表
一.TARGET SPECIFICATION: Can pass hostnames, IP addresses, networks, etc. Ex: scanme.nmap.org, micros ...
- 第一节 简单的jsp实例
1.打开Eclipse,依次点击“File” .“New” .“Other” ,选择生成动态Web项目. 2.输入项目名字,点击Finish 生成项目结构如下: 3.在WebContent目录上,单击 ...
- 液晶数字显示屏QLCDNumbe
import sys from PyQt5.QtWidgets import QApplication, QWidget, QLCDNumber, QVBoxLayout class Demo(QWi ...