HDU1890 Robotic Sort Splay tree反转,删除
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1890
题目中涉及数的反转和删除操作,需要用Splay tree来实现。首先对数列排序,得到每个数在数列中的下标x。Splay tree的每个节点标记以它为根的子树是否需要反转,用到懒惰操作,保证nlogn,在每次操作的时候Push_Down()和Push_Up。在建树的时候是数的下标为节点标号建立数,如果要询问数num[i],则把num[i]在数列中的下标旋转到根节点root,size[ch[root][0]]+已经排好序的数的数目就是答案。注意,这里因为涉及到数的反转操作,因此在Splay()操作的时候,应该先Push_Down(),然后再判断旋转操作。。
//STATUS:C++_AC_256MS_2700KB
#include <functional>
#include <algorithm>
#include <iostream>
//#include <ext/rope>
#include <fstream>
#include <sstream>
#include <iomanip>
#include <numeric>
#include <cstring>
#include <cassert>
#include <cstdio>
#include <string>
#include <vector>
#include <bitset>
#include <queue>
#include <stack>
#include <cmath>
#include <ctime>
#include <list>
#include <set>
#include <map>
using namespace std;
//using namespace __gnu_cxx;
//define
#define pii pair<int,int>
#define mem(a,b) memset(a,b,sizeof(a))
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
#define PI acos(-1.0)
//typedef
typedef __int64 LL;
typedef unsigned __int64 ULL;
//const
const int N=;
const int INF=0x3f3f3f3f;
const int MOD=,STA=;
const LL LNF=1LL<<;
const double EPS=1e-;
const double OO=1e15;
const int dx[]={-,,,};
const int dy[]={,,,-};
const int day[]={,,,,,,,,,,,,};
//Daily Use ...
inline int sign(double x){return (x>EPS)-(x<-EPS);}
template<class T> T gcd(T a,T b){return b?gcd(b,a%b):a;}
template<class T> T lcm(T a,T b){return a/gcd(a,b)*b;}
template<class T> inline T lcm(T a,T b,T d){return a/d*b;}
template<class T> inline T Min(T a,T b){return a<b?a:b;}
template<class T> inline T Max(T a,T b){return a>b?a:b;}
template<class T> inline T Min(T a,T b,T c){return min(min(a, b),c);}
template<class T> inline T Max(T a,T b,T c){return max(max(a, b),c);}
template<class T> inline T Min(T a,T b,T c,T d){return min(min(a, b),min(c,d));}
template<class T> inline T Max(T a,T b,T c,T d){return max(max(a, b),max(c,d));}
//End #define Key_value ch[ch[root][1]][0]
int pre[N],ch[N][]; //分别表示父结点,键值,左右孩子(0为左孩子,1为右孩子),根结点,结点数量
int sz[N],st[N]; //子树规模,内存池
int root,tot,top; //根节点,根节点数量,内存池容量
//题目特定数据
struct Node{
int num,idx;
}nod[N];
bool rev[N];
int n;
//debug部分copy from hh
void Treaval(int x) {
if(x) {
Treaval(ch[x][]);
printf("结点%2d:左儿子 %2d 右儿子 %2d 父结点 %2d size = %2d rev = %2d\n",x,ch[x][],ch[x][],pre[x],sz[x],rev[x]);
Treaval(ch[x][]);
}
}
void debug() {printf("%d\n",root);Treaval(root);}
//以上Debug
//新建一个结点
void NewNode(int &x,int fa,int k)
{
// if(top)x=st[--top];
// else x=++tot;
x=k;
pre[x]=fa;
sz[x]=;
rev[x]=;
ch[x][]=ch[x][]=; //左右孩子为空
} void Push_Up(int x)
{
sz[x]=sz[ch[x][]]+sz[ch[x][]]+;
} void Push_Down(int x)
{
if(rev[x]){
rev[ch[x][]]^=;
rev[ch[x][]]^=;
swap(ch[x][],ch[x][]);
rev[x]=;
}
}
//旋转,kind为1为右旋,kind为0为左旋
void Rotate(int x,int kind)
{
int y=pre[x],z=pre[y];
Push_Down(y);
Push_Down(x); //先把y的标记向下传递,再把x的标记往下传递
//类似SBT,要把其中一个分支先给父节点
ch[y][!kind]=ch[x][kind];
pre[ch[x][kind]]=y;
//如果父节点不是根结点,则要和父节点的父节点连接起来
if(z)ch[z][ch[z][]==y]=x;
pre[x]=z;
ch[x][kind]=y;
pre[y]=x;
Push_Up(y); //维护y结点,不要维护x节点,x节点会再次Push_Down,最后维护一下x节点即可
}
//Splay调整,将根为r的子树调整为goal
void Splay(int x,int goal)
{
int y,z,kind;
while(pre[x]!=goal){
//父节点即是目标位置,goal为0表示,父节点就是根结点
y=pre[x];
Push_Down(pre[y]);Push_Down(y);Push_Down(x); //设计到反转操作,要先更新,然后在判断!!
if(pre[y]==goal){
Rotate(x,ch[y][]==x);
}
else {
kind=ch[pre[y]][]==y;
//两个方向不同,则先左旋再右旋
if(ch[y][kind]==x){
Rotate(x,!kind);
Rotate(x,kind);
}
//两个方向相同,相同方向连续两次
else {
Rotate(y,kind);
Rotate(x,kind);
}
}
}
//更新根结点
Push_Up(x);
if(goal==)root=x;
}
//建树,中间结点先建立,然后分别对区间两端在左右子树建立
void BuildTree(int &x,int l,int r,int fa)
{
if(l>r)return;
int mid=(l+r)>>;
NewNode(x,fa,mid);
BuildTree(ch[x][],l,mid-,x);
BuildTree(ch[x][],mid+,r,x);
Push_Up(x);
} int cmp(Node a,Node b)
{
return a.num!=b.num?a.num<b.num:a.idx<b.idx;
} void Init()
{
root=tot=top=;
ch[root][]=ch[root][]=pre[]=sz[]=rev[]=; for(int i=;i<=n;i++){
scanf("%d",&nod[i].num);
nod[i].idx=i;
}
sort(nod+,nod+n+,cmp);
BuildTree(root,,n,);
} int Get_Max(int x)
{
Push_Down(x);
while(ch[x][]){
x=ch[x][];
Push_Down(x);
}
return x;
} void Remove()
{
if(ch[root][]==){
root=ch[root][];
pre[root]=;
}
else {
int x=Get_Max(ch[root][]);
Splay(x,root);
ch[x][]=ch[root][];
pre[ch[root][]]=x;
root=x;
pre[root]=;
Push_Up(root);
}
} int main()
{
// freopen("in.txt","r",stdin);
int i,j;
while(~scanf("%d",&n) && n)
{
Init();
for(i=;i<n;i++){
Splay(nod[i].idx,);
rev[ch[root][]]^=;
printf("%d ",i+sz[ch[root][]]);
Remove();
}
printf("%d\n",n);
}
return ;
}
HDU1890 Robotic Sort Splay tree反转,删除的更多相关文章
- HDU 1890 - Robotic Sort - [splay][区间反转+删除根节点]
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1890 Time Limit: 6000/2000 MS (Java/Others) Memory Li ...
- HDU1890 Robotic Sort[splay 序列]
Robotic Sort Time Limit: 6000/2000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Tota ...
- hdu 1890 Robotic Sort(splay 区间反转+删点)
题目链接:hdu 1890 Robotic Sort 题意: 给你n个数,每次找到第i小的数的位置,然后输出这个位置,然后将这个位置前面的数翻转一下,然后删除这个数,这样执行n次. 题解: 典型的sp ...
- hdu1890 Robotic Sort (splay+区间翻转单点更新)
Problem Description Somewhere deep in the Czech Technical University buildings, there are laboratori ...
- BZOJ 1552: [Cerc2007]robotic sort( splay )
kpm大神说可以用块状链表写...但是我不会...写了个splay.... 先离散化 , 然后splay结点加个min维护最小值 , 就可以了... ( ps BZOJ 3506 题意一样 , 双倍经 ...
- HDU 1890 Robotic Sort | Splay
Robotic Sort Time Limit: 6000/2000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others) [Pr ...
- 【BZOJ1552】[Cerc2007]robotic sort Splay
[BZOJ1552][Cerc2007]robotic sort Description Input 输入共两行,第一行为一个整数N,N表示物品的个数,1<=N<=100000.第二行为N ...
- 【bzoj1552/3506】[Cerc2007]robotic sort splay翻转,区间最值
[bzoj1552/3506][Cerc2007]robotic sort Description Input 输入共两行,第一行为一个整数N,N表示物品的个数,1<=N<=100000. ...
- Splay Tree的删除操作
Splay Tree的插入操作,搜索操作,和删除操作都实现了,那么就能够使用来解题了. 指针的删除操作的处理还是那么难的,非常多坎须要避开. 同一个坎还是坑了我好多次,就是指针传递的问题,什么时候须要 ...
随机推荐
- Django 后台搭建
# Django settings for gameadmin project. DEBUG = True TEMPLATE_DEBUG = DEBUG ADMINS = ( # ('Your Nam ...
- CodeForces 279B Books
http://codeforces.com/problemset/problem/279/B 题意 :Valera 有很多的空闲时间,所以他决定看书,给出n本书,编号1到n,和看每本书需要的时间,他看 ...
- PYTHON设计模式,创建型之工厂方法模式
我感觉和上一个差不多,可能不要动最要的地方吧... #!/usr/bin/evn python #coding:utf8 class Pizza(object): def prepare(self, ...
- 李洪强iOS开发本人集成环信的经验总结_07_监听好友请求
李洪强iOS开发本人集成环信的经验总结_07_监听好友请求 来到Appdalegate中: 遵守代理协议 设置代理 实现监听好友请求的回调的方法
- live555源码研究(二)------TaskScheduler类
一.TaskScheduler类作用 1,他是使用环境的一部分. 2,他提供了对socket触发事件的管理. 二.类TaskScheduler继承关系图 二.TaskScheduler成员函数 1,s ...
- C++动态链接库测试实例
前话 上一章节我导出了一个动态链接库 要使用该链接库,我们还需要该链接库对外公开的函数,即头文件 下面开始实例 测试实例 第一步--将动态链接库的dll.lib.和头文件导入项目中 文件目录如下: 项 ...
- C# 调用WebService的方法
很少用C#动态的去调用Web Service,一般都是通过添加引用的方式,这样的话是自动成了代理,那么动态代理调用就是我们通过代码去调用这个WSDL,然后自己去生成客户端代理.更多的内容可以看下面的两 ...
- linux 新建用户、用户组 以及为新用户分配权限
Linux 系统是一个多用户多任务的分时操作系统,任何一个要使用系统资源的用户,都必须首先向系统管理员申请一个账号,然后以这个账号的身份进入系统.用户的账号 一方面可以帮助系统管理员对使用系统的用户进 ...
- 编程之美 3.1 字符串移位包含问 复杂度(O(N*K)
分享关于编程之美3.1自己编写的代码,很简单. s2.沿着s1匹配(循环匹配,利用%Length技巧),匹配上,返回true. //BOP3.1 char src[] = "AABBCD&q ...
- [原]数据库中的partitioning和sharding
1. 如何理解定义 在中文中,partitioning和sharding都有分区的意思.从大的方面来说,这两个词所执行的动作确实也和分区相关.partitioning在很多场合是vertical pa ...