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. Windows x86 x64使用SetThreadContext注入shellcode的方式加载DLL

    一.前言 注入DLL的方式有很多,在R3就有远程线程CreateRemoteThread.SetWindowsHookEx.QueueUserApc.SetThreadContext 在R0可以使用a ...

  2. [hihoCoder]#1039 : 字符消除

    Description 小Hi最近在玩一个字符消除游戏.给定一个只包含大写字母"ABC"的字符串s,消除过程是如下进行的: 1)如果s包含长度超过1的由相同字母组成的子串,那么这些 ...

  3. 用jQuery解决弹出层的问题

    在BS 项目中 经常需要用到这种弹出层.做这种弹出层一般都会遇到下面几个问题:0,弹出层必须定义在input的下边显示.1,点击input弹出div层.2,点击div层外面任何地方,关闭div层.3, ...

  4. cJSON 使用笔记

    缘      起 最近在stm32f103上做一个智能家居的项目,其中选择的实时操作系统是 rt_thread OS v1.2.2稳定版本,其中涉及到C和java(android)端数据的交换问题,经 ...

  5. 跨浏览器实现盒阴影(box-shadow)效果

    现在流行的设计里总是使用了大量的阴影,看看Vista.win7里夸张的box阴影,mac里的阴影比比皆是.CSS3的box-shadow属性可以让我们轻松实现图层阴影效果,使我们可以不再总是依赖于使用 ...

  6. Codeforces Round #310 (Div. 1) B. Case of Fugitive set

    B. Case of Fugitive Time Limit: 20 Sec Memory Limit: 256 MB 题目连接 http://codeforces.com/contest/555/p ...

  7. linux C高手成长过程---书籍推荐

    建议学习路径: 首先先学学编辑器,vim, emacs什么的都行. 然后学make file文件,只要知道一点就行,这样就可以准备编程序了. 然后看看<C程序设计语言>K&R,这样 ...

  8. 【转】android开源项目和框架

      特效: http://www.androidviews.net/ http://www.theultimateandroidlibrary.com/ 常用效果: 1. https://github ...

  9. Timing advance of GSM(时间提前量)

    基本概念 时间提前量TA(Timing Advance)的作用是为了补偿电波传输延迟,而根本目的则是为了提高信道编解码效率.由于GSM采用TDMA,每载频8个时隙,应严格保持时隙间的同步,没有TA就无 ...

  10. MySQL错误:Can't connect to MySQL server (10060)

    转自:http://database.51cto.com/art/201107/274565.htm 当远程连接MySQL数据库的时候显示Can't connect to MySQL server ( ...