POJ 3580 SuperMemo 伸展树

题意:

维护一个序列,支持如下几种操作:

  • ADD x y D:将区间\([x,y]\)的数加上\(D\)
  • REVERSE x y:翻转区间\([x,y]\)
  • REVOLVE x y T:将区间\([x,y]\)向右循环平移\(T\)个长度
  • INSERT x P:在第\(x\)个元素后插入\(P\)
  • DELETE x:删除第\(x\)个元素
  • QUERY x y:查询区间\([x,y]\)中的最小值

分析:

ADD和REVERSE操作维护两个懒惰标记即可
REVOLVE操作本质还是CUT一段区间下来插入到别的位置(也可以REVERSE三次实现)

下面可以公开的情报:
经测试:数据的范围没有超过int,REVOLVE操作中的T没有负数,不要把add标记pushdown到null节点上,可能会溢出

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
#include <map>
#include <set>
using namespace std;
typedef long long LL;
typedef pair<int, int> PII;
#define PB push_back
#define PII pair<int, int>
#define REP(i, a, b) for(int i = a; i < b; i++)
#define PER(i, a, b) for(int i = b - 1; i >= a; i--)
#define ALL(x) x.begin(), x.end()

const int maxn = 100000 + 10;
const int INF = 0x3f3f3f3f;

int a[maxn];

struct Node {
	Node* ch[2];
	int s, v, minv;
	bool flip; int add;
	void maintain() {
		minv = min(v, min(ch[0]->minv, ch[1]->minv));
		s = ch[0]->s + ch[1]->s + 1;
	}
	int cmp(int k) {
		k -= ch[0]->s + 1;
		if(!k) return -1;
		return k < 0 ? 0 : 1;
	}
	void pushdown();
};

int tot = 0;
Node pool[maxn << 1], *null;

void Node::pushdown() {
	if(flip) {
		flip = false;
		swap(ch[0], ch[1]);
		ch[0]->flip ^= 1;
		ch[1]->flip ^= 1;
	}
	if(add) {
		if(ch[0] != null) {
			ch[0]->add += add;
			ch[0]->v += add;
			ch[0]->minv += add;
		}
		if(ch[1] != null) {
			ch[1]->add += add;
			ch[1]->v += add;
			ch[1]->minv += add;
		}
		add = 0;
	}
}

Node* newnode(int v) {
	Node* p = pool + tot; tot++;
	p->ch[0] = p->ch[1] = null;
	p->s = 1; p->v = p->minv = v;
	p->add = 0; p->flip = false;
	return p;
}

void rotate(Node* &o, int d) {
	Node* k = o->ch[d^1]; o->ch[d^1] = k->ch[d];
	k->ch[d] = o; o->maintain(); k->maintain();
	o = k;
}

void splay(Node* &o, int k) {
	o->pushdown();
	int d = o->cmp(k);
	if(d == -1) return;
	if(d == 1) k -= o->ch[0]->s + 1;
	Node* &p = o->ch[d];
	p->pushdown();
	int d2 = o->ch[d]->cmp(k);
	if(d2 == -1) { rotate(o, d^1); return; }
	int k2 = k;
	if(d2 == 1) k2 -= p->ch[0]->s + 1;
	splay(p->ch[d2], k2);
	if(d == d2) { rotate(o, d^1); rotate(o, d^1); }
	else { rotate(p, d); rotate(o, d^1); }
}

void split(Node* o, int k, Node* &left, Node* &right) {
	splay(o, k);
	left = o;
	right = o->ch[1];
	left->ch[1] = null;
	left->maintain();
}

Node* merge(Node* left, Node* right) {
	splay(left, left->s);
	left->ch[1] = right;
	left->maintain();
	return left;
}

Node* build(int l, int r) {
	if(l > r) return null;
	int mid = (l + r) / 2;
	Node* p = newnode(a[mid]);
	p->ch[0] = build(l, mid - 1);
	p->ch[1] = build(mid + 1, r);
	p->maintain();
	return p;
}

void splayInit() {
	tot = 0;
	null = new Node;
	null->ch[0] = null->ch[1] = null;
	null->s = 0; null->v = null->minv = INF;
}

int main() {
	int n, m;
	while(scanf("%d", &n) == 1) {
		splayInit();
		a[0] = INF;
		REP(i, 1, n + 1) scanf("%d", a + i);
		Node* root = build(0, n);

		scanf("%d", &m);
		char cmd[10];
		int x, y;
		while(m--) {
			scanf("%s%d", cmd, &x);
			if(cmd[0] == 'A') {
				int D; scanf("%d%d", &y, &D);
				Node *o, *left, *mid, *right;
				split(root, x, left, o);
				split(o, y-x+1, mid, right);
				mid->add += D;
				mid->v += D;
				mid->minv += D;
				root = merge(merge(left, mid), right);
			} else if(cmd[0] == 'R' && cmd[3] == 'E') {
				scanf("%d", &y);
				Node *o, *left, *mid, *right;
				split(root, x, left, o);
				split(o, y-x+1, mid, right);
				mid->flip ^= 1;
				root = merge(merge(left, mid), right);
			} else if(cmd[0] == 'R' && cmd[3] == 'O') {
				int T; scanf("%d%d", &y, &T);
				int len = y - x + 1;
				T %= len;
				if(!T) continue;
				T = y-x+1 - T;
				Node *o, *left, *midl, *midr, *right;
				split(root, x, left, o);
				split(o, T, midl, o);
				split(o, y-x+1-T, midr, right);
				root = merge(merge(merge(left, midr), midl), right);
			} else if(cmd[0] == 'I') {
				int P; scanf("%d", &P);
				Node* p = newnode(P), *left, *right;
				split(root, x+1, left, right);
				root = merge(merge(left, p), right);
			} else if(cmd[0] =='D') {
				Node* left, *mid, *right;
				split(root, x, left, mid);
				split(mid, 1, mid, right);
				root = merge(left, right);
			} else {
				scanf("%d", &y);
				Node* left, *mid, *right;
				split(root, x, left, mid);
				split(mid, y-x+1, mid, right);
				printf("%d\n", mid->minv);
				root = merge(merge(left, mid), right);
			}
		}

		delete null;
	}

	return 0;
}
posted @ 2017-12-05 13:11  AOQNRMGYXLMV  阅读(204)  评论(0编辑  收藏  举报