HDU 4441 Queue Sequence
http://acm.hdu.edu.cn/showproblem.php?pid=4441
题意:对于一个序列,每次有三种操作
insert pos 表示在pos插入一个数,这个数是最小的正数没有在序列中出现的。而且还要在某个位置插入他的相反数,使得这个序列满足队列的出入顺序(正表示进,负表示出)
remove num 表示在序列中把num以及-num两数去掉
query num 把num与-num之间的数求和输出
这题我本来实在是没有思路,看起来像维护一个线段树,这样求和好办,但是序列的长度是会变的,而且元素的绝对位置是会变的,线段树就无法解决了。
通过这题我才了解了一个新的数据结构:Splay Tree。每个节点不仅要保存元素值,还需要维护以当前节点为根的子树所含的正数个数和负数个数以及从开头到当前元素的序列和。在一棵二叉查找树种如何在第i个元素之前插入一个元素呢?我原先想构造二叉树使得后序遍历为当前序列,这样要在一个元素前插入一个节点,就在以这个节点的左子树的最右端插入就可以了,这样不怕没位置。但问题是,为了提高查找树的效率,无论用AVL Tree 还是 Splay Tree 都要用旋转操作,这一旋转就会破坏这个关系。要是旋转操作保持树的原有性质,就只能用中序:节点的左子树的所有元素都在当前元素的左边,节点的右子树的所有元素都在当前元素的右边。那如何在指定位置插入呢,那只能先断开节点和一个子树的联系,在此之间插入新元素节点再连接起来。
用Splay Tree的好处是SP树可以把一个节点提到树根并保持整棵树的性质,这样在插入、删除以及合并时更加方便,这样可以很快地把树以一个标准分为两个部分,更据偏序关系来操作。由于Splay Tree需要多次旋转,插入删除时也会更改树的结构,所以要注意节点的更新和更新的顺序!
确定当前不在序列中的最小正整数用线段树来维护就好了。这题用了两种数据结构和变异的算法,逻辑复杂,再用类封装,所以代码量比较大,我也调试了许久,问题出来节点更新和些小细节上,不过总算AC了。
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
inline int mymin(int a,int b)
{
if (a==-) return b;
if (b==-) return a;
return a>b?b:a;
}
struct segtree
{
#define sbegin 1,100000,1
int tree[<<];
segtree(){build(sbegin);}
void build(int l,int r,int rt)
{
if (l==r){tree[rt]=l;return;}
int mid=(l+r)>>;
build(l,mid,rt<<);
build(mid+,r,rt<<|);
tree[rt]=mymin(tree[rt<<],tree[rt<<|]);
}
void update(int l,int r,int rt,int p,int op)
{
if (l==r && l==p){tree[rt]=op; return;}
int mid=(l+r)>>;
if (p<=mid) update(l,mid,rt<<,p,op);
if (p>mid) update(mid+,r,rt<<|,p,op);
tree[rt]=mymin(tree[rt<<],tree[rt<<|]);
}
int query(){return tree[]; }
void insert(int p) { update(sbegin,p,-);}
void del(int p){update(sbegin,p,p); }
}*myseg;
struct spt
{ spt(){root=NULL;}
struct node
{
int data;
long long sum;
int zs,fs;
node *left,*right,*father;
node(int d=,node* a=NULL,node *b=NULL,node *c=NULL):data(d),left(a),right(b),father(c)
{sum=data;zs=data>;fs=data<;}
}*root;
void print(node *p)
{
if (p==NULL) return;
print(p->left);
printf("[%d] data: %d sum: %I64d zs: %d fs:%d | %4d %4d %4d\n",p,p->data,p->sum,p->zs,p->fs,p->father,p->left,p->right);
print(p->right);
}
void update(node *k)
{
k->sum=k->data;
if (k->left) k->sum+=k->left->sum;
if (k->right) k->sum+=k->right->sum;
k->zs=k->data>;
if (k->left) k->zs+=k->left->zs;
if (k->right) k->zs+=k->right->zs;
k->fs=k->data<;
if (k->left) k->fs+=k->left->fs;
if (k->right) k->fs+=k->right->fs;
}
void zig(node *k)
{
node* fa=k->father;
fa->left=k->right;
if (k->right) k->right->father=fa;
k->right=fa;
k->father=fa->father;
fa->father=k;
update(fa);
update(k);
if (!k->father) return;
if (k->father->left==fa)
k->father->left=k;
else
k->father->right=k;
update(k->father);
}
void zag(node *k)
{
node* fa=k->father;
fa->right=k->left;
if (k->left) k->left->father=fa;
k->left=fa;
k->father=fa->father;
fa->father=k;
update(fa);
update(k);
if (!k->father) return;
if (k->father->left==fa)
k->father->left=k;
else
k->father->right=k;
update(k->father);
}
void splay(node *k,node *&root)
{
while (k->father)
{
node *fa=k->father;
if (fa->father==NULL)
{
if (k==fa->left) zig(k);
else zag(k);
}
else
{
node *gf=fa->father;
if (fa==gf->left && k==fa->left)
{
zig(fa);
zig(k);
}
if (fa==gf->left && k==fa->right)
{
zag(k);
zig(k);
}
if (fa==gf->right && k==fa->left)
{
zig(k);
zag(k);
}
if (fa==gf->right && k==fa->right)
{
zag(fa);
zag(k);
}
}
}
root=k;
}
node *findmax(node *&p)
{
node *t=p;
while (t->right) t=t->right;
splay(t,p);
return t;
}
node* insert(int data,int tp)
{
if (root==NULL) {root=new node(data); return root;}
if (root->zs+root->fs<tp)
{
findmax(root);
root->right=new node(data);
root->right->father=root;
update(root);
return root->right;
}
find(tp);
node *t=root->left;
root->left=new node(data);
root->left->father=root;
root->left->left=t;
if (t) t->father=root->left;
update(root->left);
update(root);
return root->left;
}
node* insert2(int data,int tp)
{
if (root->fs<tp)
{
findmax(root);
root->right=new node(data);
root->right->father=root;
update(root);
return root->right;
}
node *q=__find2(tp,root);
if (q) splay(q,root);
node *t=root->left;
root->left=new node(data);
root->left->father=root;
root->left->left=t;
if (t) t->father=root->left;
update(root->left);
update(root);
return root->left;
}
node* __find(int tp,node *root)
{
if (root==NULL) return NULL;
int tem=;
if (root->left) tem=root->left->zs+root->left->fs;
if (root->left && tp<=tem ) return __find(tp,root->left);
if (tem+==tp) return root;
return __find(tp-tem-,root->right);
}
node* __find2(int tp,node *root)
{
if (root==NULL) return NULL;
int tem=;
if (root->left) tem=root->left->fs;
if (root->left && tp<=tem ) return __find2(tp,root->left);
if (tem+(root->data<)==tp) return root;
return __find2(tp-tem-(root->data<),root->right);
}
node* find(int tp)
{
node *q=__find(tp,root);
if (q) splay(q,root);
return q;
}
node* join(node *a,node *b)
{
if (a)a->father=NULL;
if (b) b->father=NULL;
if (!a || !b) return (node *)((int)a|(int)b);
node *t=findmax(a);
t->right=b;
b->father=t;
update(t);
return t;
}
void remove(node *q)
{
splay(q,root);
node *tem=root;
root=join(root->left,root->right);
delete tem;
}
void del(node *p)
{
if (p==NULL) return;
del(p->left);
del(p->right);
delete p;
}
~spt(){del(root);}
}*mysp;
struct pair
{
spt::node *first,*second;
pair(spt::node *a=NULL,spt::node *b=NULL):first(a),second(b){}
}path[];
void work(char type,int n)
{
if (type=='i')
{
int data=myseg->query();
myseg->insert(data);
spt::node *a=mysp->insert(data,n+);
mysp->splay(a,mysp->root);
int zs=;
if (a->left) zs+=a->left->zs;
spt::node *b=mysp->insert2(-data,zs+);
path[data]=pair(a,b);
}
if (type=='r')
{
pair t=path[n];
mysp->remove(t.first);
mysp->remove(t.second);
myseg->del(n);
}
if (type=='q')
{
long long ans=;
pair t=path[n];
mysp->splay(t.second,mysp->root);
if (mysp->root->left) ans+=mysp->root->left->sum;
mysp->splay(t.first,mysp->root);
ans-=mysp->root->data;
if (mysp->root->left) ans-=mysp->root->left->sum;
printf("%I64d\n",ans);
}
}
int main()
{
int n,cas=;
while (~scanf("%d",&n))
{
printf("Case #%d:\n",++cas);
mysp=new spt;
myseg=new segtree;
char cmd[];
int t;
while (n--)
{
scanf("%s%d",cmd,&t);
work(cmd[],t);
}
delete mysp;
delete myseg;
}
}
代码
HDU 4441 Queue Sequence的更多相关文章
- HDU 4441 Queue Sequence(优先队列+Treap树)(2012 Asia Tianjin Regional Contest)
Problem Description There's a queue obeying the first in first out rule. Each time you can either pu ...
- HDU 4441 Queue Sequence(splay)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4441 题意:一个数列,三种操作:(1)插入:找到没在当前数列中的最小的正整数i,将其插在位置p之后,并 ...
- HDU 5860 Death Sequence(死亡序列)
p.MsoNormal { margin: 0pt; margin-bottom: .0001pt; text-align: justify; font-family: Calibri; font-s ...
- HDU 1711 Number Sequence(数列)
HDU 1711 Number Sequence(数列) Time Limit: 10000/5000 MS (Java/Others) Memory Limit: 32768/32768 K (Ja ...
- HDU 1005 Number Sequence(数列)
HDU 1005 Number Sequence(数列) Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Jav ...
- HDU 5860 Death Sequence(递推)
HDU 5860 Death Sequence(递推) 题目链接http://acm.split.hdu.edu.cn/showproblem.php?pid=5860 Description You ...
- HDU 1560 DNA sequence(DNA序列)
HDU 1560 DNA sequence(DNA序列) Time Limit: 15000/5000 MS (Java/Others) Memory Limit: 32768/32768 K ...
- HDU 1005 Number Sequence(数论)
HDU 1005 Number Sequence(数论) Problem Description: A number sequence is defined as follows:f(1) = 1, ...
- HDU 1711 Number Sequence (字符串匹配,KMP算法)
HDU 1711 Number Sequence (字符串匹配,KMP算法) Description Given two sequences of numbers : a1, a2, ...... , ...
随机推荐
- jpa 支持(sql)JDBC标准语句
=====================dao================================ package com.jb.xs.Dao.impl; import java.uti ...
- 说下Fedora下把SpiderMonkey放入Eclipse内编译的过程
首先要知道SpiderMonkey是个什么玩意 详细的可以看看这里(当然,如果你有google翻译的话看起来也一样费劲,你可以在语言那里选择中文.看完了再转回英文-因为中文有很多文档都没有的,比如:B ...
- stl map高效遍历删除的方法 [转]
for(:iter!=mapStudent.end():) { if((iter->second)>=aa) { //满足删除条件,删除当前结点,并指 ...
- phantomjs
PhantomJS是以WebKit为核心并提供JavaScript编程接口(API)的无界面浏览器. 它提供对web标准的 快速 并且 原生 的支持: DOM操作.CSS选择符.JSON.Canvas ...
- 深入Delphi -- Windows 消息机制
http://www.txsz.net/xs/delphi/3/Windows%20%E6%B6%88%E6%81%AF%E6%9C%BA%E5%88%B6.htm Windows 消息机制 by m ...
- 用NDK编译lua库
Android.mk是这样的 LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) LOCAL_MODULE := lua LOCAL_SRC_FILE ...
- C#中正则表达式进行忽略大小写的字符串替换
在C#里要进行忽略大小写的字符串替换,用string的Replace是很难做到的,即使花了天大的力气做到了,效率仍然是很低的,正确的方法应该是使用正则表达式. 要使用正则表达式,首先需要引用命名空间: ...
- Eclipse中SVN的安装步骤(两种)和用法
一.给安装EclipseSVN,最常见的有两种方式:手动方式和使用安装向导方式.详细过程例如以下: 方式一:手动安装 1.从官网下载site-1.6.9.zip文件,网址是:subclipse.tig ...
- 关于View端
View--------------Request 1 URL vs n View 同一个URL可以对应多个View, HTML(通过Request请求获得) 例如SAO项目中的step1--> ...
- 【JavaScript】新浪微博ajax请求后改变地址栏url,但页面不跳转的方案解析
新浪微博当你弹出一个视频的时候再点下一页时,原视频还在,而且地址栏的url的页数变了.对于这种网上讨论最多的方案有以下几种: 一.通过锚点Hash实现在这方面其实国内很早就有做了,比如淘宝画报,通过的 ...