HDU - 1890 Robotic Sort 伸展树

题目链接:https://cn.vjudge.net/problem/HDU-1890

题意:每次将第i个位置到第i大的数所在位置 之间的数进行翻转,输出的是第i大的数所在的位置

题解:按照1-n建树,原序列排序,每次把节点 a[i].id 放到顶部,位置即为左子树数目+i,然后删除顶部节点

#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;
const int N = 2e5 + 10;
struct Splaytree {
	int nex[N][2]; 
	int f[N];
	int sz[N];  // 子树节点个数 
	int val[N]; // 当前节点的值
	int cnt[N]; // 当前节点个数 
	int rev[N]; // 翻转标记 
	int root;
	int tot;
	void init() {
		root = 0;
		tot = 0;
		f[0] = sz[0] = nex[0][0] = nex[0][1] = 0;
		rev[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;
		rev[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];
		if(nex[rt][0]) sz[rt] += sz[nex[rt][0]];
		if(nex[rt][1]) sz[rt] += sz[nex[rt][1]];
	}
	void build(int &rt, int l, int r, int fa) { // 构建 
		if(l > r) return;
		int mid = (l + r) >> 1;
		rt = mid;	
		val[rt] = mid;
		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_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(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 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);
		}
	}

}p;
int n;
struct node {
	int x, id;
	bool operator <(const node &b)const {
		if(x == b.x) return id < b.id;
		else return x < b.x;
	}
}a[N];
int main() {
    while(~scanf("%d", &n) && n) {
    	for(int i = 1; i <= n; i++) {
    		scanf("%d", &a[i].x);
			a[i].id = i;
		}
		sort(a + 1, a + 1 + n);
		p.init();
		p.build(p.root, 1, n, 0);
		p.pushup(p.root);
		for(int i = 1; i <= n; i++) {
			p.splay(a[i].id, 0);

			printf("%d%c", p.sz[p.nex[p.root][0]] + i, " \n"[i == n]);
			p.update_rev(p.nex[p.root][0]);
			p.delete_rt();
		}
	}
    return 0;
}

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值