BZOJ1503 郁闷的出纳员

本文介绍了一道关于Splay树区间操作的经典题目——“郁闷的出纳员”,通过此题详细讲解了如何利用Splay树实现高效的数据更新与查询操作。文章重点介绍了在面对加薪、减薪等区间操作时,如何运用懒标记(Lazy Tag)进行优化,并讨论了在选择节点时需要注意的细节。

BZOJ 1503 郁闷的出纳员


解析:题目不难, 算是Splay区间操作入门题, 主要就是考虑每次减薪操作时, 直接将当前的薪水小于min限制的人员全部删掉即可, 加薪的时候直接在root处打上tag 然后在合适的时候进行pushdown即可, 注意select单个node的时候, 一定样pushdown(),不然会WA.


Source:

#include
#include
#include
#include
#include
#include
#include

using namespace std;

inline void R(int &v)
{
	char c=0;
	bool p=true;
	v=0;
	while(!isdigit(c))
	{
		if(c=='-')
			p=false;
		c=getchar();
	}
	while(isdigit(c))
	{
		v=(v<<3)+(v<<1)+(c^'0');
		c=getchar();
	}
	if(!p)
		v=-v;
}

const int MAXN=1e6;
const int INF=~0u>>1;

template
struct memorypool 
{
    T buf[size], *tail, *st[size];
    int top;
    inline T *alloc() { return top ? st[--top] : tail++; }
    inline void recycle(T *x) { st[top++] = x; }
    memorypool() : top(0), tail(buf) {}
};

template
struct Splay {
    enum Relation { L = 0, R = 1 };
    struct node {
        node *child[2], *parent, **root;
        T value, lazy;
        int size, count;
        inline void init(node *parent, node **root, const T &value) 
		{
			this->parent = parent, this->value = value, this->root = root;
			this->count = this->size = 1, this->lazy = 0, child[L] = child[R] = NULL; 
		}
       // inline Relation relation() { return this == parent->child[L] ? L : R; }
        inline void recycle(memorypool &pool) 
		{
            if (child[L]) pool.recycle(child[L]);
            if (child[R]) pool.recycle(child[R]);
        }
		inline void updata(const T &delta) 
		{
            if (this->value != INF && this->value != -INF) this->value += delta;
            this->lazy += delta;
        }
        inline void pushdown() 
		{
            if (lazy) {
                if (child[L]) child[L]->updata(lazy);
                if (child[R]) child[R]->updata(lazy);
                lazy = 0;
            }
        }
		inline Relation relation() { return this == parent->child[L] ? L : R; }
		inline void maintain() { pushdown(), size = count + (child[L] ? child[L]->size : 0) + (child[R] ? child[R]->size : 0); }
        inline void rotate() 
		{
            pushdown();
            Relation x = relation();
            node *oldParent = parent;
            if (oldParent->parent) oldParent->parent->child[oldParent->relation()] = this;
            parent = oldParent->parent, oldParent->child[x] = child[x ^ 1];
            if (child[x ^ 1]) child[x ^ 1]->parent = oldParent;
            child[x ^ 1] = oldParent, oldParent->parent = this, oldParent->maintain(), maintain();
            if (!parent) *root = this;
        }
		inline void splay(node *targetParent = NULL) 
		{
            while (parent != targetParent) {
                parent->pushdown(), pushdown();
                if (parent->parent == targetParent) rotate();
                else {
                    parent->parent->pushdown();
                    if (parent->relation() == relation()) parent->rotate(), rotate();
                    else rotate(), rotate();
                }
            }
        }
		inline node *precursor() 
		{
            splay();
            node *v = child[L];
            while (v->child[R]) v = v->child[R];
            return v;
        }
        inline node *successor() 
		{
            splay();
            node *v = child[R];
            while (v->child[L]) v = v->child[L];
            return v;
        }
	inline int rank() { return child[L] ? child[L]->size : 0; }
    } *root;
    memorypool pool;
    Splay() : root(NULL) { insert(INF), insert(-INF); }
	 inline node *find(const T &value) 
	 {
        node *v = root;
        while (v && value != v->value) v->pushdown(), v = (value < v->value ? v->child[L] : v->child[R]);
        return v ? (v->splay(), v) : NULL;
    }
	inline node *insert(const T &value) 
	{
        node *v = find(value);
        if (v) return v->count++, v->maintain(), v;
        node **target = &root, *parent = NULL;
        while (*target) parent = *target, parent->pushdown(), parent->size++, target = (value < parent->value ? &parent->child[L] : &parent->child[R]);
        return *target = pool.alloc(), (*target)->init(parent, &root, value), (*target)->splay(), root;
    }
	inline int rank(const T &value)
	{
		node *v=find(value);
		if(v) return v->rank();
		else
		{
			node *v=insert(value);
			register int ans=v->rank();
			return erase(v), ans;
		}
	}
	inline const T &precursor(const T &value)
	{
		node *v=find(value);
		if(v) return v->precursor()->value;
		else
		{
			node *v=insert(value);
			const T &ans=v->precursor()->value;
			return erase(v), ans;
		}
	}
	inline const T &successor(const T &value)
	{
		node *v=find(value);
		if(v) return v->successor()->value;
		else
		{
			node *v=insert(value);
			const T &ans=v->successor()->value;
			return erase(v), ans;
		}
	}
	inline void updata(const T &value) { root->updata(value); }
    inline const T &select(int k) {
        k++;
        node *v = root;
        while (v->pushdown(), !(v->rank() < k && v->rank() + v->count >= k)) v = (k <= v->rank() ? v->child[L] : (k -= v->rank() + v->count, v->child[R]));
        return v->splay(), v->value;
    }
    inline void erase(node *l, node *r) {
        node *pre = l->precursor(), *suc = r->successor();
        pre->splay(), suc->splay(pre), suc->child[L]->recycle(pool);
        pool.recycle(suc->child[L]), suc->child[L] = NULL, suc->maintain(), pre->maintain();
    }
    inline void erase(node *v) { v->count > 1 ? v->count-- : erase(v, v); }
    inline void erase(const T &l, const T &r) {
        node *vl = find(l), *vr = find(r);
        if (!vl) vl = insert(l);
        if (!vr) vr = insert(r);
        erase(vl, vr);
    }
inline int size() { return root->size - 2; }
};

Splay splay;

int main()
{
	int n,min,x,ans,cnt=0;
	char c[10];
	R(n),R(min);
	while(n--)
	{
		scanf("%s",c),R(x);
		if(c[0]=='I') 
		{
			if(x>=min)
			{
				splay.insert(x);
				cnt++;
			}
		}
		else if(c[0]=='A') splay.updata(x);
		else if(c[0]=='S') splay.updata(-x),splay.erase(-INF+1,min-1);
		else if(c[0]=='F')
		{
			splay.erase(-INF+1,min-1);
			if(x>splay.size())
				cout<<"-1"<<'\n';
			else
				cout<

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值