平衡树-splay 入门

splay保证复杂度 是通过 每次进行操作后 都把该节点提到根节点

题意

每次将一段区间进行翻转 求最终序列

我们要反转区间的话可以像 线段树一样打标记
pushdown 函数
我们可以将 key 值看做成 下标顺序
进行插入
每次操作的时候我们先将l-1 提到树根
再将r+1 作为其右子树 那么 r+1 的左子树就都是key 小于 r+1的了 最后再中序遍历输出

核心

rotate (把左旋和右旋结合到一起)和splay函数

#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 = 1e6 + 10;
int n, m , k;
int rt, idx;
struct node {
	int v, fa, s[2], siz, flag;
} tr[N];
#define ls tr[i].s[0]
#define rs tr[i].s[1]
void pushup(int i) {
	tr[i].siz = tr[ls].siz + tr[rs].siz + 1;
}
void pushdown(int i) {
	if(tr[i].flag) {
		swap(ls, rs);
		tr[ls].flag ^= 1;
		tr[rs].flag ^= 1;
		tr[i].flag = 0;
	}
}
void rotate(int x) {
	int y = tr[x].fa, z = tr[y].fa;
	int k = tr[y].s[1] == x;
	tr[z].s[tr[z].s[1] == y] = x, tr[x].fa = z;
	tr[y].s[k] = tr[x].s[k ^ 1], tr[tr[x].s[k ^ 1]].fa = y;
	tr[x].s[k ^ 1] = y, tr[y].fa = x;
	pushup(y), pushup(x);
}

void splay(int i, int k) {
	while(tr[i].fa != k) {
		int x = tr[i].fa;
		int y = tr[x].fa;
		if(y != k) {
			if(tr[x].s[0] == i ^ tr[y].s[0] == x) {
				rotate(i);
			} else
				rotate(x);
		}
		rotate(i);
	}
	if(!k) rt = i;
}

void insert(int v) {
	int i = rt;
	int p = 0;
	while(i) {
		p = i;
		i = tr[i].s[tr[i].v < v];
	}
	i = ++idx;
	if(p)tr[p].s[tr[p].v < v] = i;
	tr[i].v = v;
	tr[i].fa = p;
	tr[i].siz = 1;
	splay(i, 0);
}
int get_s(int k, int i) {
	//xcbj
	pushdown(i);
	if(k <= tr[ls].siz) return get_s(k, ls);
	if(k == tr[ls].siz + 1) return i;
	return get_s(k - tr[ls].siz - 1, rs);
}
void get_ans(int i) {
	//xcbj
	pushdown(i);
	if(ls) {
		get_ans(ls);
	}
	if(tr[i].v >= 1 && tr[i].v <= n) cout << tr[i].v  <<" ";
	if(rs) {
		get_ans(rs);
	}
}
void solve() {
	cin >> n >> m;
	fer(i, 0, n + 1) {
		insert(i);
	}
	fer(i, 1, m) {
		int l, r;
		cin >> l >> r;
		l = get_s(l, rt);
		r = get_s(r + 2, rt);
		splay(l, 0);
		splay(r, l);
		tr[tr[r].s[0]].flag ^= 1;
	}
	get_ans(rt);
}
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、付费专栏及课程。

余额充值