P1486 [NOI2004] 郁闷的出纳员(平衡树 splay)

link

做法

平衡树基本操作 注意 一些细节
pushup 的顺序
splay的rotate顺序
pushup时应该加1
注意 边界 是l 所以应该是先插入极小值

#include <bits/stdc++.h>
using namespace  std;
//#define  int long long
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int> pii;
typedef vector<int> vi;
#define fi first
#define se second
#define pb  push_back
#define inf 1ll<<62
#define endl "\n"
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))
#define de_bug(x) cerr << #x << "=" << x << endl
#define all(a) a.begin(),a.end()
#define IOS   std::ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
#define  fer(i,a,b)  for(int i=a;i<=b;i++)
#define  der(i,a,b)  for(int i=a;i>=b;i--)
const int mod = 1e9 + 7;
const int N = 6e6 + 10;
int n, m , k;

struct node {
	int siz;
	int l, r;
	int val;
	int fa;
	int s[2];
#define ls(i) tr[i].s[0]
#define rs(i) tr[i].s[1]
#define fa(x)  tr[x].fa
#define val(x)  tr[x].val

} tr[N];
int rt;
void pushup(int i) {
	tr[i].siz = tr[ls(i)].siz + tr[rs(i)].siz + 1;
}
void rotate(int x) {
	int y = fa(x), z = fa(y);
	int k = rs(y) == x;
	tr[z].s[rs(z) == y] = x, fa(x) = z;
	tr[y].s[k] = tr[x].s[k ^ 1], fa(tr[x].s[k ^ 1]) = y;
	tr[x].s[k ^ 1] = y, fa(y) = x;
	pushup(y);
	pushup(x);
}
void splay(int x, int k) {
	while(fa(x) != k) {
		int y = fa(x);
		int z = fa(y);
		if(z != k) {
			//折线
			if(rs(z) == y ^ rs(y) == x) {
				rotate(x);
			} else rotate(y);
		}
		//直线
		rotate(x);
	}
	if(!k) rt = x;
}
int idx;
void insert(int val) {
	int u = rt;
	int fa = 0;
	while(u) {
		fa = u;
		u = tr[u].s[val > tr[u].val];
	}
	u = ++idx;
	if(fa) tr[fa].s[tr[fa].val < val] = u;
	fa(u) = fa;
	val(u) = val;
	tr[u].siz = 1;
	splay(u, 0);
}
int get_node(int val) {
	int u = rt;
	int ans = 0;
	while(u) {
		if(val(u) >= val) {
			ans = u;
			u = ls(u);
		} else u = rs(u);
	}
	return ans;
}
//第k大
int get_ans(int i, int k) {
	if(tr[rs(i)].siz >= k) return get_ans(rs(i), k);
	else if(tr[rs(i)].siz + 1 == k) return tr[i].val;
	else {
		return  get_ans(ls(i), k - 1 - tr[rs(i)].siz);
	}
}
//第k小
int get_ans1(int i, int k) {
	if(tr[ls(i)].siz >= k) return get_ans1(ls(i), k);
	else if(tr[ls(i)].siz + 1 == k) return tr[i].val;
	else {
		return get_ans1(rs(i), k - 1 - tr[ls(i)].siz);
	}
}
int cnt;
void solve() {
	insert(-(1 << 30));
	insert((1 << 30));
	int l = 1, r = 2;
	cin >> n >> m;
	int tmp = 0;
	fer(i, 1, n) {
		char op;
		int x;
		cin >> op >> x;
		if(op == 'I') {
			if(x < m)continue;
			++cnt;
			int t = x - tmp;
			insert(t);
		} else if(op == 'A') {
			tmp += x;
		} else if(op == 'S') {
			tmp -= x;
			int r = get_node(m - tmp);
			splay(r, 0);
			splay(l, r);
			rs(l) = 0;
			pushup(l);
			pushup(r);
		} else if(op == 'F') {
			if(tr[rt].siz - 2 < x ) cout << -1 << endl;
			else cout << get_ans1(rt, tr[rt].siz - x) + tmp << endl;
		}

	}
	cout << cnt - tr[rt].siz + 2 << endl;
}
int main() {
	IOS;
	int _ = 1;
	//cin>>_;
	while( _-- )
		solve();
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值