您的位置:首页 > 其它

【bzoj1503】[NOI2004]郁闷的出纳员

2017-03-02 21:29 369 查看
大名鼎鼎的平衡树模板题,话说我当初学平衡树的时候到底去干嘛了,这道题都没做= =。

这道题实际上区间操作蛮水的,因为全部都加减根本不用在树的两侧添加结点,所以直接根节点打标记就好了,每次减少工资的时候查询有没有员工离开了公司。

这个题有一个坑点就是如果工资一开始就少于K就不需要添加进去了,因为这个坑点这道题我调了好久.

#include<cstdio>
#include<iostream>
#include<cstring>
#include<string>
#include<algorithm>
//1.splay写的不熟练
//2.坑点,注意m以下的数直接不要插了
//3.注意对size的处理,勤更新
using namespace std;
const int N=100010;
int n,m;
int sz,root;
int ch
[2],fa
,size
,cnt
,key
,tag
;
inline void clear(int x){size[x]=tag[x]=cnt[x]=ch[x][0]=ch[x][1]=fa[x]=key[x]=0;}
inline int get(int x){return ch[fa[x]][1]==x;}
void pushdown(int x)
{
if (!x||tag[x]==0)return;
if (ch[x][0])key[ch[x][0]]+=tag[x],tag[ch[x][0]]+=tag[x];
if (ch[x][1])key[ch[x][1]]+=tag[x],tag[ch[x][1]]+=tag[x];
tag[x]=0;
}
inline void updata(int x)
{
if (!x)return;
size[x]=cnt[x];
if (ch[x][0])size[x]+=size[ch[x][0]];
if (ch[x][1])size[x]+=size[ch[x][1]];
}
inline void rotate(int x)
{
pushdown(fa[x]);pushdown(x);
int old=fa[x],oldf=fa[old],which=get(x);
ch[old][which]=ch[x][which^1],fa[ch[old][which]]=old;
ch[x][which^1]=old;fa[old]=x;fa[x]=oldf;
if (oldf)ch[oldf][ch[oldf][1]==old]=x;
updata(old),updata(x);
}
inline void splay(int x)
{
for(int old;(old=fa[x]);rotate(x))
if (fa[old])rotate(get(old)==get(x)?old:x);
root=x;
}
inline void insert(int x)
{

if (!root){root=++sz;size[sz]=cnt[sz]=1;tag[sz]=fa[sz]=ch[sz][0]=ch[sz][1]=0;key[sz]=x;return;}
int now=root,old=0;
while(1)
{
pushdown(now);
if (key[now]==x)
{
cnt[now]++;
updata(now);
updata(old);
splay(now);
break;
}
old=now;
now=ch[now][key[now]<x];
if (now==0)
{
fa[++sz]=old;
tag[sz]=ch[sz][0]=ch[sz][1]=0;
ch[old][key[old]<x]=sz;
cnt[sz]=size[sz]=1;
key[sz]=x;updata(old);
splay(sz);
break;
}
}
}
inline int findpos(int x)
{
int ans=0,now=root;
while(1)
{
pushdown(now);
if (x<key[now])now=ch[now][0];
else
{
ans+=(ch[now][0]?size[ch[now][0]]:0);
if (x==key[now]){splay(now);return ans+1;}
ans+=cnt[now],now=ch[now][1];
}
}
}
inline int findnth(int x)
{
if (x>size[root])return -1;
int now=root;
while(1)
{
//      cout<<"now "<<now<<' '<<key[ch[now][0]]<<' '<<x<<size[ch[now][1]]<<' '<<cnt[now]<<endl;
pushdown(now);
if (ch[now][1]&&x<=size[ch[now][1]])now=ch[now][1];
else
{
int temp=(ch[now][1]?size[ch[now][1]]:0)+cnt[now];
if (x<=temp)return key[now];
x-=temp;now=ch[now][0];
}
}
}
inline int pre()
{
int now=ch[root][0];
while(ch[now][1])
now=ch[now][1];
return now;
}
inline void del(int x)
{
findpos(x);
if (cnt[root]>1){cnt[root]--;updata(root);return;}
if (!ch[root][1]&&!ch[root][0]){clear(root);root=0;return;}
if (!ch[root][0]){int oldroot=root;root=ch[root][1];fa[root]=0;clear(oldroot);updata(root);return;}
if (!ch[root][1]){int oldroot=root;root=ch[root][0];fa[root]=0;clear(oldroot);updata(root);return;}
int leftbig=pre(),oldroot=root;
splay(leftbig);
ch[root][1]=ch[oldroot][1];
fa[ch[oldroot][1]]=root;
clear(oldroot);
updata(root);
return;
}
inline void solve(int x)
{
insert(x);
//  cout<<"solve root "<<root<<endl;
//  for (int i=1;i<=sz;++i)
//  printf("%d %d %d %d %d %d\n",i,key[i],fa[i],ch[i][0],ch[i][1],tag[i]);
clear(ch[root][0]);
ch[root][0]=0;
updata(root);
del(x);
}
int add(int d)
{
key[root]+=d;
tag[root]+=d;
pushdown(root);
updata(root);
}
int main()
{
//  freopen("std.in","r",stdin);
//  freopen("std.out","w",stdout);
char s[3];
int qx;
int tot=0,k=0;
scanf("%d%d",&n,&m);
for (int i=1;i<=n;++i)
{
scanf("%s",s);
scanf("%d",&qx);
if (s[0]=='I'&&qx>=m)insert(qx),tot++;
else if (s[0]=='A')add(qx);
else if (s[0]=='S')add(-qx),solve(m),k++;
else if (s[0]=='F')printf("%d\n",findnth(qx));
}
printf("%d",tot-size[root]);
return 0;
}


1.splay写的不熟练

2.坑点,注意m以下的数直接不要插了

3.注意对size的处理,勤更新
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: