转载请注明出处,谢谢http://blog.csdn.net/ACM_cxlove?viewmode=contents by---cxlove
题目:每次有三种操作
insert pos 表示在pos插入一个数,这个数是最小的正数没有在序列中出现的。而且还要在某个位置插入他的相反数
remove num 表示把num以及-num去掉
query num 把num与-num之间的数求和输出
http://acm.hdu.edu.cn/showproblem.php?pid=4441
首先说一下insert操作
对于需要插入的那个数,维护一个线段树表示区间最值就OK了,随意搞吧。
那么对于插入的正数,位置已经告诉了,就简单了,对于那个负数,要求的位置是最右边的满足条件的。
其实题目要求的就是正数的顺序和负数的是一样的。
那么如果当前数字i前面有n个正数,那么表示-i前面也有n个负数,而且又需要是最右边的
就是第 n+1个负数的左边,如果没有n+1个负数,那就看插到最后(所以代码中有一个判断)
那么怎么找第n+1个负数呢,只需要维护一个值,表示负数的个数就行了,我还维护了正数有多少个,其实没啥用,TAT
然后是remove操作,只要记录num以及-num在Splay中的编号就可以了。
那么 就可以很轻松的通过编号找到结点,删除
我存的是编号,那么在删除的时候,先旋转至根,找到他的左边有多少个数,这样得到他的位置,就好处理了
最后是query操作,由于 我们存了编号
那么通过Splay很快能找到中间的区间,维护一个区间和就OK了
这种数据结构题,代码量很大,给现场短时候1A的队伍跪烂啊,需要非常注意细节。
写代码的时候简单地加了点注释
#include<iostream>
#include<cstdio>
#include<map>
#include<cstring>
#include<cmath>
#include<vector>
#include<algorithm>
#include<set>
#include<string>
#include<queue>
#define inf 1<<30
#define M 200005
#define N 200005
#define maxn 300005
#define eps 1e-10
#define zero(a) fabs(a)<eps
#define Min(a,b) ((a)<(b)?(a):(b))
#define Max(a,b) ((a)>(b)?(a):(b))
#define pb(a) push_back(a)
#define mp(a,b) make_pair(a,b)
#define mem(a,b) memset(a,b,sizeof(a))
#define LL long long
#define lson step<<1
#define rson step<<1|1
#define MOD 1000000009
#define sqr(a) ((a)*(a))
#define Key_value ch[ch[root][1]][0]
#pragma comment(linker, "/STACK:1024000000,1024000000")
using namespace std;
struct Splay_tree{
LL sum[N];
int size[N],pre[N],val[N],tot;
int ch[N][2],tot1,root,s[N],tot2,cnt[N][2]; //cnt[0]表示的是正数个数,cnt[1]表示的是负数个数
//debug部分copy from hh
void Treaval(int x) {
if(x) {
Treaval(ch[x][0]);
printf("结点%2d:左儿子 %2d 右儿子 %2d 父结点 %2d size = %2d ,val = %2c \n",x,ch[x][0],ch[x][1],pre[x],size[x],val[x]);
Treaval(ch[x][1]);
}
}
void debug() {printf("%d\n",root);Treaval(root);}
//以上Debug
inline void NewNode(int &r,int k,int father){
r=++tot1;
ch[r][0]=ch[r][1]=0;
cnt[r][0]=k>0;
cnt[r][1]=k<0;
sum[r]=k;
pre[r]=father;
size[r]=1;
val[r]=k;
}
inline void Push_Up(int x){
if(x==0) return ;
int l=ch[x][0],r=ch[x][1];
size[x]=size[l]+size[r]+1;
cnt[x][0]=cnt[l][0]+cnt[r][0]+(val[x]>0);
cnt[x][1]=cnt[l][1]+cnt[r][1]+(val[x]<0);
sum[x]=(LL)sum[l]+sum[r]+val[x];
}
inline void Init(){
tot1=tot2=root=tot=0;
ch[root][0]=ch[root][1]=pre[root]=size[root]=sum[0]=cnt[0][0]=cnt[0][1]=0;
val[root]=0;
NewNode(root,0,0);
NewNode(ch[root][1],0,root);
Push_Up(ch[root][1]);
Push_Up(root);
}
inline void Rotate(int x,int kind){
int y=pre[x];
ch[y][!kind]=ch[x][kind];
pre[ch[x][kind]]=y;
if(pre[y])
ch[pre[y]][ch[pre[y]][1]==y]=x;
pre[x]=pre[y];
ch[x][kind]=y;
pre[y]=x;
Push_Up(y);
}
inline void Splay(int r,int goal){
while(pre[r]!=goal){
if(pre[pre[r]]==goal)
Rotate(r,ch[pre[r]][0]==r);
else{
int y=pre[r];
int kind=(ch[pre[y]][0]==y);
if(ch[y][kind]==r){
Rotate(r,!kind);
Rotate(r,kind);
}
else{
Rotate(y,kind);
Rotate(r,kind);
}
}
}
Push_Up(r);
if(goal==0) root=r;
}
inline void RotateTo(int k, int goal) {
int x=root;
while(k!=size[ch[x][0]]+1){
if (k<=size[ch[x][0]]){
x=ch[x][0];
}else{
k-=(size[ch[x][0]]+1);
x=ch[x][1];
}
}
Splay(x,goal);
}
inline int Get_Kth(int r,int k){
int t=size[ch[r][0]]+1;
if(t==k) return r;
if(t>k) return Get_Kth(ch[r][0],k);
else return Get_Kth(ch[r][1],k-t);
}
inline int Insert(int pos,int k){
tot++;
RotateTo(pos,0);
RotateTo(pos+1,root);
NewNode(Key_value,k,ch[root][1]);
Push_Up(ch[root][1]);
Push_Up(root);
return Key_value;
}
inline void Delete(int r){
tot--;
Splay(r,0);
int pos=size[ch[r][0]];
RotateTo(pos,0);
RotateTo(pos+2,root);
s[tot2++]=Key_value;
Key_value=0;
Push_Up(ch[root][1]);
Push_Up(root);
}
//找第n+1个负数的位置
inline int find(int x,int n){
int l=ch[x][0],r=ch[x][1];
if(cnt[l][1]==n&&val[x]<0) {Splay(x,0);return size[ch[root][0]];}
else if(cnt[l][1]>=n+1) return find(l,n);
else return find(r,n-cnt[l][1]-(val[x]<0));
}
inline void InOrder(int r){
if(r==0)
return;
InOrder(ch[r][0]);
printf("%d ",val[r]);
InOrder(ch[r][1]);
}
inline void Print(){
RotateTo(1,0);
RotateTo(tot+2,root);
InOrder(Key_value);
printf("\n");
}
}splay;
struct Segment_tree{
int left,right,mmin;
}L[N*4];
int position[N][2];
void Push_Up(int step){
L[step].mmin=min(L[lson].mmin,L[rson].mmin);
}
void Bulid(int step,int l,int r){
L[step].left=l;
L[step].right=r;
if(l==r){
L[step].mmin=l;
return;
}
int m=(l+r)/2;
Bulid(lson,l,m);
Bulid(rson,m+1,r);
Push_Up(step);
}
//flag为1表示是插入,flag为0表示是删除
void Update(int step,int pos,int flag){
if(L[step].left==pos&&pos==L[step].right){
if(flag) L[step].mmin=inf;
else L[step].mmin=L[step].left;
return ;
}
int m=(L[step].left+L[step].right)/2;
if(pos<=m) Update(lson,pos,flag);
else Update(rson,pos,flag);
Push_Up(step);
}
void Insert(int pos){
int num=L[1].mmin;
position[num][0]=splay.Insert(pos+1,num);
splay.Splay(position[num][0],0);
int n=splay.cnt[splay.ch[splay.root][0]][0]; //表示在+i之前有多少个正数
//将-i插入到第n+1个负数左边
if(splay.cnt[splay.root][1]<=n){
int m=splay.size[splay.root]-2+1;
position[num][1]=splay.Insert(m,-num);
Update(1,num,1); //插入线段树
}
else{
int m=splay.find(splay.root,n); //表示第n+1个负数是第m个数
position[num][1]=splay.Insert(m,-num);
Update(1,num,1); //插入线段树
}
}
void Remove(int k){
splay.Delete(position[k][0]);
splay.Delete(position[k][1]);
Update(1,k,0); //从线段树中移除
}
LL Query(int k){
splay.Splay(position[k][0],0);
splay.Splay(position[k][1],splay.root);
return splay.sum[splay.ch[splay.ch[splay.root][1]][0]];
}
int main(){
int cas=0,q;
while(scanf("%d",&q)!=EOF){
printf("Case #%d:\n",++cas);
splay.Init();
Bulid(1,1,q);
while(q--){
char str[10];int k;
scanf("%s%d",str,&k);
if(str[0]=='i') Insert(k);
else if(str[0]=='r') Remove(k);
else printf("%I64d\n",Query(k));
// splay.Print();
}
}
return 0;
}