2437. Splay(模板题)

活动 - AcWing

给定一个长度为 nn 的整数序列,初始时序列为 {1,2,…,n−1,n}

序列中的位置从左到右依次标号为 1∼n

我们用 [l,r] 来表示从位置 l 到位置 r 之间(包括两端点)的所有数字构成的子序列。

现在要对该序列进行 m 次操作,每次操作选定一个子序列 [l,r],并将该子序列中的所有数字进行翻转。

例如,对于现有序列 1 3 2 4 6 5 7,如果某次操作选定翻转子序列为 [3,6],那么经过这次操作后序列变为 1 3 5 6 4 2 7

请你求出经过 mm 次操作后的序列。

输入格式

第一行包含两个整数 n,m。

接下来 m 行,每行包含两个整数 l,r,用来描述一次操作。

输出格式

共一行,输出经过 m 次操作后的序列。

数据范围

1≤n,m≤105
1≤l≤r≤n

输入样例:
6 3
2 4
1 5
3 5
输出样例:
5 2 1 4 3 6

解析: 

#include <iostream>
#include <string>
#include <cstring>
#include <cmath>
#include <ctime>
#include <algorithm>
#include <utility>
#include <stack>
#include <queue>
#include <vector>
#include <set>
#include <math.h>
#include <map>
#include <sstream>
#include <deque>
#include <unordered_map>
#include <unordered_set>
#include <bitset>
#include <stdio.h>
#include <tuple>
using namespace std;
typedef long long LL;
//#define int LL
#define ld long double
const LL INF = 0x3f3f3f3f3f3f3f3f;
typedef unsigned long long ULL;
typedef pair<long long, long long> PLL;
typedef pair<int, int> PII;
typedef pair<double, double> PDD;
const int inf = 0x3f3f3f3f;
const LL Mod = 998244353;
const ld eps = 1e-12;
const int N = 1e5 + 10, M = 1e6 + 10;
int n, m;
struct Node {
	int s[2], p, v;
	int flg, size;
	void init(int _v, int _p) {
		v = _v, p = _p;
		size = 1;
	}
}tr[N];
int idx;
int root;

void up(int u) {
	tr[u].size = tr[tr[u].s[0]].size + tr[tr[u].s[1]].size + 1;
}
void down(int u) {
	if (tr[u].flg) {
		swap(tr[u].s[0], tr[u].s[1]);
		tr[tr[u].s[0]].flg ^= 1;
		tr[tr[u].s[1]].flg ^= 1;
		tr[u].flg = 0;
	}
}
void rotate(int x) {
	int y = tr[x].p, z = tr[y].p;
	int k = tr[y].s[1] == x;
	tr[z].s[tr[z].s[1] == y] = x, tr[x].p = z;
	tr[y].s[k] = tr[x].s[k ^ 1], tr[tr[x].s[k ^ 1]].p = y;
	tr[x].s[k ^ 1] = y, tr[y].p = x;
	up(y), up(x);
}
void splay(int x,int k) {
	while (tr[x].p != k) {
		int y = tr[x].p, z = tr[y].p;
		if (z != k) {
			if ((tr[y].s[1] == x) ^ (tr[z].s[1] == y))rotate(x);
			else rotate(y);
		}
		rotate(x);
	}
	if (!k)root = x;
}
void insert(int v) {
	int u = root, p = 0;
	while (u)p = u, u = tr[u].s[v > tr[u].v];
	u = ++idx;
	if (p)tr[p].s[v > tr[p].v] = u;
	tr[u].init(v, p);
	splay(u, 0);
}
int get_k(int k) {
	int u = root;
	while (1) {
		down(u);
		if (tr[tr[u].s[0]].size >= k)u = tr[u].s[0];
		else if (tr[tr[u].s[0]].size + 1 == k)return u;
		else k -= tr[tr[u].s[0]].size + 1, u = tr[u].s[1];
	}
	return -1;
}
void output(int u) {
	down(u);
	if (tr[u].s[0])output(tr[u].s[0]);
	if (tr[u].v >= 1 & tr[u].v <= n)printf("%d ", tr[u].v);
	if (tr[u].s[1])output(tr[u].s[1]);
}
signed main() {
	cin >> n >> m;
	for (int i = 0; i <= n + 1; i++) {
		insert(i);
	}
	int l, r;
	while (m--) {
		scanf("%d%d", &l, &r);
		l = get_k(l), r = get_k(r + 2);
		splay(l, 0), splay(r, l);
		tr[tr[r].s[0]].flg ^= 1;
	}
	output(root);
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值