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的更多相关文章

  1. 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 ...

  2. HDU 4441 Queue Sequence(splay)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4441 题意:一个数列,三种操作:(1)插入:找到没在当前数列中的最小的正整数i,将其插在位置p之后,并 ...

  3. HDU 5860 Death Sequence(死亡序列)

    p.MsoNormal { margin: 0pt; margin-bottom: .0001pt; text-align: justify; font-family: Calibri; font-s ...

  4. HDU 1711 Number Sequence(数列)

    HDU 1711 Number Sequence(数列) Time Limit: 10000/5000 MS (Java/Others) Memory Limit: 32768/32768 K (Ja ...

  5. HDU 1005 Number Sequence(数列)

    HDU 1005 Number Sequence(数列) Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Jav ...

  6. HDU 5860 Death Sequence(递推)

    HDU 5860 Death Sequence(递推) 题目链接http://acm.split.hdu.edu.cn/showproblem.php?pid=5860 Description You ...

  7. HDU 1560 DNA sequence(DNA序列)

    HDU 1560 DNA sequence(DNA序列) Time Limit: 15000/5000 MS (Java/Others)    Memory Limit: 32768/32768 K  ...

  8. HDU 1005 Number Sequence(数论)

    HDU 1005 Number Sequence(数论) Problem Description: A number sequence is defined as follows:f(1) = 1, ...

  9. HDU 1711 Number Sequence (字符串匹配,KMP算法)

    HDU 1711 Number Sequence (字符串匹配,KMP算法) Description Given two sequences of numbers : a1, a2, ...... , ...

随机推荐

  1. 关闭IE窗口

    $a=(New-Object -comObject Shell.Application).Windows() ($a|?{$_.locationname -eq "人力与人才信息管理系统&q ...

  2. IOS 手机助手及越狱助手推荐

    快装系列 1 快装助手(PC版) http://pc.kuaiapp.cn/ 2 快装越狱助手(PC版)http://www.kuaiapp.cn 3 快装商店(手机版)http://yueyu.ku ...

  3. 58 web框架Argo代码分析

    贴地址:https://github.com/58code/Argo 核心jar javax.servlet-api 3.0.1 guice 3.0 velocity 1.7 框架使用 servlet ...

  4. android复制数据库到SD卡(网上搜集,未经验证)

    android中使用sqlite.复制assets下的数据库到SD卡.支持大于1M的文件 如果使用SD卡,需要在AndroidManifest.xml中设置权限 <uses-permission ...

  5. ajax开发框架和XMLhttpRequest、responseText、responseXml和JSON的应用

    1 AJAX开发框架 2 A 初始化XMLHttpRequest对象 3 B指定响应处理函数 4 C发出HTTP请求 5 D处理服务器返回的信息 6 数据格式提要 6 优点 6 缺点 7 解析 JSO ...

  6. STL中的优先级队列(priority_queue)的自己实现priqueue

    这篇文章主要介绍堆(最大堆和最小堆),以及一些系统对一些任务,比如线程,进程做调度的时候,所采用的优先级队列. 主要思想就是,做一个最大堆(任务的权重最大的在顶端),把顶端的任务取出,重新做一个堆,处 ...

  7. Eclipse中R文件不能自动生成

       R文件不能自动生成主要是因为编译有错误,这时你想什么办法都是没有用的,clean, fix properties,都不是从根上解决问题.    R文件主要是自动生成资源文件的id的,里边静态子类 ...

  8. iOS开发——UI篇Swift篇&UIWebView

    UIWebView //返回按钮事件 @IBAction func backButtonClick() { self.navigationController?.popViewControllerAn ...

  9. javascript实现单例模式

    1.简单实现单例模式: var singleTon = function(){ var _pria = 'private value'; var show_pria = function(){ con ...

  10. [原创]SSAS-引用维度与多数据源、多数据源视图引发分区错误

    背景:       最近有个项目,有32家分公司,集团总部需要取这个32家分公司数据做分析,由于每个分公司的数据都比较庞大,所以最终方案是每个分公司一个DW,在cube搭建过程中将每个公司数据作为一个 ...