您的位置:首页 > 其它

NOI2004 郁闷的出纳员

2014-09-17 21:09 369 查看
往事不堪回首。。

这个题目花了2天时间才A了。

思路照搬SnowyJone大牛:http://www.cnblogs.com/w007878/p/3453023.html Orz。。


此处可找到数据:http://tieba.baidu.com/p/1217076472

真是虐心的两天,整个人都瘦了。。

当然也算值了,为的就是splay的模板大计!

操作中较为难办的就是相同数和删除区间。

相同数解决方法:保证每个数都不同,用num记录其个数

删除区间[l, r]:实际上是将l的前驱p,r的后继q,将p移动到q的子节点,直接删除p的右子树,然后更新即可。相比对序列操作的l 和 r可能不存在,需要特殊处理一下。

再者就是各种细节:

  1. 初始工资小于MIN的不算踢出的。。

  2. 各种PUSHUP,PUSHDOWN注意。

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <cstdlib>
#include <cmath>
#include <utility>
#include <vector>
#include <queue>
#include <map>
#include <set>
#define max(x,y) ((x)>(y)?(x):(y))
#define min(x,y) ((x)>(y)?(y):(x))
#define INF 0x3f3f3f3f
#define MAXN 100005

using namespace std;

int cnt, rt;
int Add[MAXN],ans;

struct Tree{
int key, num, size, fa, son[2];
}T[MAXN];

inline void PushUp(int x)
{
T[x].size=T[T[x].son[0]].size+T[T[x].son[1]].size+T[x].num;
}

inline void PushDown(int x)
{
if(Add[x])
{
if(T[x].son[0])
{
T[T[x].son[0]].key+=Add[x];
Add[T[x].son[0]]+=Add[x];
}
if(T[x].son[1])
{
T[T[x].son[1]].key+=Add[x];
Add[T[x].son[1]]+=Add[x];
}
Add[x]=0;
}
}

inline int Newnode(int key, int fa) //新建一个节点并返回
{
++cnt;
T[cnt].key=key;
T[cnt].num=T[cnt].size=1;
T[cnt].fa=fa;
T[cnt].son[0]=T[cnt].son[1]=0;
return cnt;
}

inline void Rotate(int x, int p) //0左旋 1右旋
{
int y=T[x].fa;
PushDown(y);
PushDown(x);
T[y].son[!p]=T[x].son[p];
T[T[x].son[p]].fa=y;
T[x].fa=T[y].fa;
if(T[x].fa)
T[T[x].fa].son[T[T[x].fa].son[1] == y]=x;
T[x].son[p]=y;
T[y].fa=x;
PushUp(y);
PushUp(x);
}

void Splay(int x, int To) //将x节点移动到To的子节点中
{
while(T[x].fa != To)
{
if(T[T[x].fa].fa == To)
Rotate(x, T[T[x].fa].son[0] == x);
else
{
int y=T[x].fa, z=T[y].fa;
int p=(T[z].son[0] == y);
if(T[y].son[p] == x)
Rotate(x, !p), Rotate(x, p); //之字旋
else
Rotate(y, p), Rotate(x, p); //一字旋
}
}
if(To == 0) rt=x;
}

int GetPth(int p, int To) //返回第p小的节点 并移动到To的子节点中
{
if(!rt || p > T[rt].size) return 0;
int x=rt;
while(x)
{
PushDown(x);
if(p >= T[T[x].son[0]].size+1 && p <= T[T[x].son[0]].size+T[x].num)
break;
if(p > T[T[x].son[0]].size+T[x].num)
{
p-=T[T[x].son[0]].size+T[x].num;
x=T[x].son[1];
}
else
x=T[x].son[0];
}
Splay(x, 0);
return x;
}

int Find(int key) //返回值为key的节点 若无返回0 若有将其转移到根处
{
if(!rt) return 0;
int x=rt;
while(x)
{
PushDown(x);
if(T[x].key == key) break;
x=T[x].son[key > T[x].key];
}
if(x) Splay(x, 0);
return x;
}

int Prev() //返回根节点的前驱 非重点
{
if(!rt || !T[rt].son[0]) return 0;
int x=T[rt].son[0];
while(T[x].son[1])
{
PushDown(x);
x=T[x].son[1];
}
Splay(x, 0);
return x;
}

int Succ() //返回根结点的后继 非重点
{
if(!rt || !T[rt].son[1]) return 0;
int x=T[rt].son[1];
while(T[x].son[0])
{
PushDown(x);
x=T[x].son[0];
}
Splay(x, 0);
return x;
}

void Insert(int key) //插入key值
{
if(!rt)
rt=Newnode(key, 0);
else
{
int x=rt, y=0;
while(x)
{
PushDown(x);
y=x;
if(T[x].key == key)
{
T[x].num++;
T[x].size++;
break;
}
T[x].size++;
x=T[x].son[key > T[x].key];
}
if(!x)
x=T[y].son[key > T[y].key]=Newnode(key, y);
Splay(x, 0);
}
}

void Delete(int l, int r) //删除值在[l, r]中的节点
{
if(!Find(l)) Insert(l), ans--;
int p=Prev();
if(!Find(r)) Insert(r), ans--;
int q=Succ();
if(!p && !q)
{
ans+=T[rt].size;
rt=0;
return;
}
if(!p)
{
ans+=T[T[rt].son[0]].size;
T[rt].son[0]=0;
PushUp(rt);
return;
}
if(!q)
{
Splay(p, 0);
ans+=T[T[rt].son[1]].size;
T[rt].son[1]=0;
PushUp(rt);
return;
}
Splay(p, q);
if(T[p].son[1])
ans+=T[T[p].son[1]].size;
T[p].son[1]=0;
PushUp(p);
PushUp(q);
}

int N, MIN, k;
char ch;
int main()
{
scanf("%d %d", &N, &MIN);
while(N--)
{
scanf(" %c %d", &ch, &k);
switch (ch)
{
case 'I':
if(k >= MIN)
Insert(k);
break;
case 'A':
T[rt].key+=k;
Add[rt]+=k;
break;
case 'S':
T[rt].key-=k;
Add[rt]-=k;
Delete(-INF, MIN-1);
break;
case 'F':
if(T[rt].size-k+1>0)
printf("%d\n", T[GetPth(T[rt].size-k+1, 0)].key);
else
printf("-1\n");
}
}
printf("%d\n", ans);
return 0;
}


View Code
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: