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. jQuery实现等比例缩放大图片让大图片自适应页面布局

    通常我们处理缩略图是使用后台代码(PHP..net.Java等)根据大图片生成一定尺寸的缩略图,来供前台页面调用,当然也有使用前台javascript脚本将加载后的大图强行缩放,变成所谓的缩略图,这种 ...

  2. C++ Vector 使用心得 [转]

    标准库Vector类型 使用需要的头文件:#include <vector>Vector:Vector 是一个类模板.不是一种数据类型. Vector<int>是一种数据类型. ...

  3. java 编译带包文件

    问题   假设两个文件:     D:\workspace\com\A.java     D:\workspace\com\B.java 两个文件都有:     package com;   如何编译 ...

  4. 关闭IE窗口

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

  5. 用javascript实现简体和繁体字间的转换

    <html> <head> <meta http-equiv="Content-Type" content="text/html; char ...

  6. Effective Objective-C 2.0 Reading Notes

    1. Literal Syntax NSString *someString = @"Effective Objective-C 2.0"; NSNumber *someNumbe ...

  7. SharedObject使用:在FluorineFx.net与Flex中使用共享对象维护在线用户列表实例【转】

    一.添加一个新的FluorineFx的服务类项目OnLineService,删除原有的Sample.cs,并添加一个用户类定义与一个ApplicationAdpater类:如下: /*-- User. ...

  8. 【JavaScript】JS跨域设置和取Cookie

    cookie 是存储于访问者的计算机中的变量.每当同一台计算机通过浏览器请求某个页面时,就会发送这个 cookie.你可以使用 JavaScript 来创建和取回 cookie 的值.本文主要JS怎样 ...

  9. iOS开发——控制器OC篇&UINavigationController&UITabBarController详解

    UINavigationController&UITabBarController详解 一:UINavigationController 控制器的属性: UINavigationControl ...

  10. Cocos2D-X2.2.3学习笔记9(处理重力感应事件,移植到Android加入两次返回退出游戏效果)

    这节我们来学习Cocos2d-x的最后一节.怎样处理重力感应事件.移植到Android后加入再按一次返回键退出游戏等.我这里用的Android.IOS不会也没设备呃 效果图不好弄,由于是要移植到真机上 ...