POJ - 3580 SuperMemo 伸展树

题目链接:https://cn.vjudge.net/problem/POJ-3580#author=0

伸展树学习:

很全:https://blog.csdn.net/qq_33184171/article/details/73549164

图:https://blog.csdn.net/wr132/article/details/50599747

效率:https://www.cnblogs.com/vamei/archive/2013/03/21/2964092.html

链接:dongxicheng.org/structure/splay-tree/

 

#include <iostream>
#include <cstdio>
using namespace std;
#define INF 2e9 + 10
const int N = 2e5 + 10;
struct Splaytree {
	int nex[N][2]; 
	int f[N];
	int sz[N];  // 子树节点个数 
	int val[N]; // 当前节点的值
	int cnt[N]; // 当前节点个数 
	int laz[N]; // 添加标记 
	int rev[N]; // 翻转标记 
	int minn[N];
	int root;
	int tot;
	void init() {
		root = 0;
		tot = 0;
		f[0] = sz[0] = nex[0][0] = nex[0][1] = 0;
		rev[0] = laz[0] = 0;
		cnt[0] = 0;
	}
	void newnode(int rt, int v, int fa) {
		f[rt] = fa;
		sz[rt] = 1;
		val[rt] = v;
		cnt[rt] = 1;
		minn[rt] = v;
		laz[rt] = 0;
		nex[rt][0] = nex[rt][1] = 0;
	} 
	void delnode(int rt) {
		f[rt] = sz[rt] = val[rt] = cnt[rt] = 0;
		nex[rt][0] = nex[rt][1] = 0;
	}
	void pushup(int rt) {
		if(!rt) return;
		sz[rt] = cnt[rt];
		minn[rt] = val[rt];
		if(nex[rt][0]) sz[rt] += sz[nex[rt][0]], minn[rt] = min(minn[rt], minn[nex[rt][0]]);
		if(nex[rt][1]) sz[rt] += sz[nex[rt][1]], minn[rt] = min(minn[rt], minn[nex[rt][1]]);
	}
	void build(int &rt, int l, int r, int fa) { // 构建 
		if(l > r) return;
		int mid = (l + r) >> 1;
		rt = mid;
		minn[rt] = val[rt];
		newnode(rt, val[rt], fa);
		cnt[rt] = 1;
		build(nex[rt][0], l, mid - 1, rt);
		build(nex[rt][1], mid + 1, r, rt);
		pushup(rt);
	}
	void update_add(int rt, int v) { // 更新 
		if(rt) {
			laz[rt] += v;
			val[rt] += v;
			minn[rt] += v;
		}
	}
	void update_rev(int rt) {
		if(rt) {
			nex[rt][0] ^= nex[rt][1] ^= nex[rt][0] ^= nex[rt][1];
			rev[rt] ^= 1;
		}
	}
	void pushdown(int rt) {
		if(!rt) return;
		if(laz[rt]) {
			update_add(nex[rt][0], laz[rt]);
			update_add(nex[rt][1], laz[rt]);
			laz[rt] = 0;
		}
		if(rev[rt]) {
			update_rev(nex[rt][0]);
			update_rev(nex[rt][1]);
			rev[rt] = 0;
		}
	}
	void rotate(int x, int k) { // 0:左旋 1:右旋  
		int y = f[x];
		int z = f[y];
		pushdown(y);
		pushdown(x);
		nex[y][!k] = nex[x][k];
		if(nex[x][k]) f[nex[x][k]] = y;
		f[x] = z;
		if(z) nex[z][nex[z][1] == y] = x;
		f[y] = x;
		nex[x][k] = y;
		pushup(y);
		pushup(x);
	}
	void splay(int x, int goal) { // x 旋转到 goal下面 
		while(f[x] != goal) {
			if(f[f[x]] == goal) rotate(x, nex[f[x]][0] == x);
			else {
				int y = f[x], z = f[y];
				int K = (nex[z][0] == y);
				if(nex[y][K] == x) rotate(x, !K), rotate(x, K);
				else rotate(y, K), rotate(x, K);
			}
		} 
		pushup(x);
		if(goal == 0) root = x;
	}
	int search(int rt, int x) { // 查询权值为x的节点 
		if(nex[rt][0] && val[rt] > x) return search(nex[rt][0], x);
		else if(nex[rt][1] && val[rt] < x) return search(nex[rt][1], x);
		else return rt;
	}
	int extreme(int rt, int k) { // 子树最值节点 0小 1大 
		while(nex[rt][k]) rt = nex[rt][k];
		splay(rt, 0);
		return rt;
	} 
	int getkth(int rt, int k) { // 得到第k个 
		pushdown(rt);
		if(sz[nex[rt][0]] < k && k <= sz[nex[rt][0]] + cnt[rt]) return rt;
		else if(sz[nex[rt][0]] >= k) return getkth(nex[rt][0], k);
		else return getkth(nex[rt][1], k - sz[nex[rt][0]] - cnt[rt]);
	} 
	int prec(int x) { // 前驱 
		int k = search(root, x);
		splay(k, 0);
		if(val[k] < x) return k;
		return extreme(nex[k][0], 1); 
	}
	int sufc(int x) { // 后继 
		int k = search(root, x);
		splay(k, 0);
		if(val[k] > x) return k;
		return extreme(nex[k][1], 0); 
	}
	void insert(int x) { // 插入 不管序列 只用权值 
		int y = search(root, x);
		if(val[y] == x) {
			cnt[y]++;
			sz[y]++;
			for(int k = y; k; k = f[k]) pushup(k);
			splay(y, 0);
		} else {
			int p = prec(x);
			int s = sufc(x);
			splay(p, 0);
			splay(s, p);
			newnode(++tot, x, nex[root][1]);
			nex[nex[root][1]][0] = tot;
			for(int k = nex[root][1]; k; k = f[k]) pushup(k);
		}
	}
	void insert_k(int k, int x) { // 第k个后面插一个数 按照序列 
		int l = getkth(root, k);
		int r = getkth(root, k + 1);
		splay(l, 0);
		splay(r, l);
		newnode(++tot, x, r);
		nex[r][0] = tot;
		for(int k = r; k; k = f[k]) pushdown(k), pushup(k);
		splay(r, 0);
	}
	void delete_(int x) { // 删除 某权值 
		int y = search(root, x);
		if(val[y] != x) return;
		if(cnt[y] > 1) {
			cnt[y]--;
			sz[y]--;
			for(int k = y; k; k = f[k]) pushup(k);
		}  else if(nex[y][0] == 0 || nex[y][1] == 0) {
			int z = f[y];
			nex[z][nex[z][1] == y] = nex[y][nex[y][0] == 0];
			f[nex[y][nex[y][0] == 0]] = z;
			delnode(y);
			for(int k = z; k; k = f[k]) pushup(k);
		} else {
			int p = prec(x);
			int s = sufc(x);
			splay(p, 0);
			splay(s, p);
			nex[nex[root][1]][0] = 0;
			delnode(nex[nex[root][1]][0]);
			for(int k = s; k; k = f[k]) pushup(k);
		}
	}
	void delete_k(int k) { // 删除第k个 
		splay(getkth(root, k - 1), 0);
		splay(getkth(root, k + 1), root);
		nex[nex[root][1]][0] = 0;
		delnode(nex[nex[root][1]][0]);
		pushup(nex[root][1]);
		pushup(root);
	} 
	int getmin(int l, int r) { // 区间最小 
		int x = getkth(root, l - 1);
		int y = getkth(root, r + 1);
		splay(x, 0);
		splay(y, x);
	//	cout << y << endl;
		return minn[nex[y][0]];
	}
	int getrank(int x) { // 某权值的排名 
		int k = search(root, x);
		splay(k, 0);
		return sz[nex[k][0]] + 1;
	}
	void add(int l, int r, int v) { // 区间加 
		int x = getkth(root, l - 1);
		int y = getkth(root, r + 1);
		splay(x, 0);
		splay(y, x);
		update_add(nex[y][0], v);
	}
	void reversal(int l, int r) { // 区间翻转 
		int x = getkth(root, l - 1);
		int y = getkth(root, r + 1);
		splay(x, 0);
		splay(y, x);
		update_rev(nex[y][0]);
	}
	void exchange(int l1, int r1, int l2, int r2) { // 区间交换 
		int x = getkth(root, l2 - 1);
		int y = getkth(root, r2 + 1);
		splay(x, 0);
		splay(y, x);
		int tmp = nex[y][0];
		nex[y][0] = 0;
		x = getkth(root, l1 - 1);
		y = getkth(root, l1);
		splay(x, 0);
		splay(y, x);
		nex[y][0] = tmp;
		f[tmp] = y;
	} 
	int rt_left(int rt) { // 子树  最左 
		for(pushdown(rt); nex[rt][0]; pushdown(rt)) rt = nex[rt][0];
		return rt;
	}
	int rt_right(int rt){ // 子树 最右 
		for(pushdown(rt); nex[rt][1]; pushdown(rt)) rt = nex[rt][1];
		return rt;
	}
	void delete_rt() { // 删除 根节点 
		if(nex[root][0] == 0) {
			root = nex[root][1];
			f[root] = 0;
		} else {
			int y = rt_right(nex[root][0]);
			splay(y, root);
			nex[y][1] = nex[root][1];
			f[nex[root][1]] = y;
			root = y;
			f[root] = 0;
			pushup(root);
		}
	}
	void pint(int rt){
	    if(!rt) return;
	    pushdown(nex[rt][0]);
		pint(nex[rt][0]);
	    printf("%d f[] = %d sz[] = %d lson = %d rson = %d val[] = %d mi[] = %d \n",rt , f[rt], sz[rt], nex[rt][0], nex[rt][1], val[rt], minn[rt]);
	    pushdown(nex[rt][1]);
		pint(nex[rt][1]);
	    pushup(rt);
	}
	void debug(){
	    printf("ROOT = %d <---\n",root);
	    pushdown(root);
	    pint(root);
	}
}p;
int n, m;
int main() {
	scanf("%d", &n);
	p.init();
	p.val[1] = -INF;
	p.val[n + 2] = INF;
	for(int i = 2; i <= n + 1; i++) scanf("%d", &p.val[i]);
	p.tot = n + 2;
	p.build(p.root, 1, n + 2, 0);
	p.pushup(p.root);
	scanf("%d", &m);
	char op[10];
	int l, r, x;
	for(int i = 1; i <= m; i++) {
		scanf("%s", op);
		if(op[0] == 'A') {
			scanf("%d %d %d", &l, &r, &x);
			l++, r++;
			p.add(l, r, x);
		} else if(op[0] == 'I') {
			scanf("%d %d", &l, &x);
			l++;
			p.insert_k(l, x);
		} else if(op[0] == 'M') {
			scanf("%d %d", &l, &r);
			l++, r++;
			printf("%d\n", p.getmin(l , r));
		} else if(op[0] == 'D') {
			scanf("%d", &l);
			l++;
			p.delete_k(l );
		} else if(op[3] == 'E') {
			scanf("%d %d", &l, &r);
			l++, r++;
			p.reversal(l, r);
		} else {
			scanf("%d %d %d", &l, &r, &x);
			l++, r++;
			x = x % (r - l + 1);
			if(x) p.exchange(l, r - x, r - x + 1, r);
		}
	} 
//	p.debug();
	return 0;
}
 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值