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;
}
}
代码