题意: 对一个序列进行区间增减,区间翻转,区间移动,插入,删除,求区间最小值。
解法: 正常情况下这种折磨序列的题一向是splay的菜,而这次发现,Treap原来也有这种战斗力,而且在编程复杂度上,个人感觉比splay简单一点。
其实就是原来的Treap加上了砍树与合并两个操作,把每次的操作区间‘砍’出来,一通乱搞完接回去。而splay是把区间旋转出来操作。时间复杂度方面,依靠于Treap的随机性,也就是nlogn啦。
/* **********************************************
Author : Nero
Created Time: 2013-9-3 13:08:39
Problem id : POJ 3580
Problem Name: SuperMemo
*********************************************** */
#include <stdio.h>
#include <string.h>
#include <algorithm>
using namespace std;
#define REP(i,a,b) for(int i=(a); i<(int)(b); i++)
#define clr(a,b) memset(a,b,sizeof(a))
const int INF = 0x3f3f3f3f;
// w的大根堆
// Be careful for NULL point
// Treap
struct Node {
Node *l,*r;
int v,delta,rev,size,minx,w;
void up() {
minx = v;
size = 1;
if(l) size += l->size, minx = min(minx, l->minx);
if(r) size += r->size, minx = min(minx, r->minx);
}
void down() {
if(delta) {
if(l) l->delta += delta, l->v += delta, l->minx += delta;
if(r) r->delta += delta, r->v += delta, r->minx += delta;
delta = 0;
}
if(rev) {
swap(l,r);
if(l) l->rev ^= 1;
if(r) r->rev ^= 1;
rev = 0;
}
}
}*root = NULL, *list = NULL;
inline int sz(Node *o) { return o ? o->size : 0; }
int ran() {
static int ranx = 123456789;
ranx += (ranx<<2) + 1;
return ranx;
}
void New_node(Node *&o, int val) {
if(list == NULL) {
Node *tt = new Node[100];
for(int i = 0; i < 100; i ++) {
tt[i].w = ran();
tt[i].r = list;
list = tt + i;
}
}
o = list;
list = o->r;
o->l = o->r = NULL;
o->v = o->minx = val;
o->size = 1;
o->delta = o->rev = 0;
}
void Reuse(Node *o) { if(o) { o->r = list; list = o; } }
// 切树,把前num个节点划分到p,其他划分到q。
void cut(Node *o, Node *&p, Node *&q, int num) {
if(num == 0) {
p = NULL; q = o;
} else if(num == sz(o)) {
p = o; q = NULL;
} else {
o->down();
if(num <= sz(o->l)) {
q = o;
cut(o->l,p,q->l,num);
q->up();
} else {
p = o;
cut(o->r,p->r,q,num-sz(o->l)-1);
p->up();
}
}
}
void merge(Node *&o, Node *p, Node *q) {
if(!p || !q) {
o = p ? p : q;
} else {
if(p->w > q->w) {
p->down();
o = p;
merge(o->r,p->r,q);
} else {
q->down();
o = q;
merge(o->l,p,q->l);
}
o->up();
}
}
void insert(Node *&o, int pos, int val) {
if(o == NULL) {
New_node(o,val);
} else {
o->down();
if(sz(o->l) >= pos) {
insert(o->l,pos,val);
if(o->l->w > o->w) {
Node* temp = o;
o = o->l;
o->down();
temp->l = o->r;
o->r = temp;
o->r->up();
}
} else {
insert(o->r,pos-sz(o->l)-1,val);
if(o->r->w > o->w) {
Node* temp = o;
o = o->r;
o->down();
temp->r = o->l;
o->l = temp;
o->l->up();
}
}
o->up();
}
}
void add(int l, int r, int val) {
Node *a, *b, *c;
cut(root,a,b,l-1);
cut(b,b,c,r-l+1);
b->v += val;
b->minx += val;
b->delta += val;
merge(a,a,b);
merge(root,a,c);
}
void remove(int pos) {
Node *a, *b, *c;
cut(root,a,b,pos-1);
cut(b,b,c,1);
merge(root,a,c);
Reuse(b);
}
int query(int l, int r) {
Node *a, *b, *c;
cut(root,a,b,l-1);
cut(b,b,c,r-l+1);
int ret = b->minx;
merge(a,a,b);
merge(root,a,c);
return ret;
}
void reverse(int l, int r) {
Node *a, *b, *c;
cut(root,a,b,l-1);
cut(b,b,c,r-l+1);
b->rev ^= 1;
merge(a,a,b);
merge(root,a,c);
}
void revolve(int l, int m, int r) {
Node *a, *b, *c, *d;
cut(root,a,b,l-1);
cut(b,b,c,m-l+1);
cut(c,c,d,r-m);
merge(a,a,c);
merge(a,a,b);
merge(root,a,d);
}
int main() {
int n,d,nq,a,b;
char s[10];
scanf("%d", &n);
for(int i = 0; i < n; i ++) {
scanf("%d", &d);
insert(root,i,d);
}
scanf("%d", &nq);
while(nq--) {
scanf("%s", s);
if(s[0] == 'A') {
scanf("%d%d%d", &a, &b, &d);
add(a,b,d);
} else if(s[0] == 'I') {
scanf("%d%d", &a, &d);
insert(root,a,d);
} else if(s[0] == 'D') {
scanf("%d", &a);
remove(a);
} else if(s[0] == 'M') {
scanf("%d%d", &a, &b);
printf("%d\n", query(a,b));
} else if(s[3] == 'E') {
scanf("%d%d", &a, &b);
reverse(a,b);
} else {
scanf("%d%d%d", &a, &b, &d);
d = (d % (b-a+1) + (b-a+1)) % (b-a+1);
if(d) revolve(a,b-d,b);
}
}
return 0;
}