思路:
区间的一系列操作, 还有翻转什么的,显然Splay
主要说一下 那个循环右移的操作吧
次数先对总长度取模, 因为相当于有循环节。
然后 这个操作 相当于 把一个区间分成两个子区间, 把后面挪到前面。
假设两个区间是 [s1, e1]和 [s2, e2]
那么先把s2-1 转到根, e2+1 转到根的下面, 将e2转到e2+1的下面,将 e2+1的左子树 切下来。
这样就把后一个区间拿出来了, 同样的操作 将s1-1转到根, s1 转到根的下面, 插到 s1左子树即可。
#include
#include
#include
using namespace std;
const int maxn = 200000 + 10;
int n, m;
int num[maxn];
const int inf = 0x3f3f3f3f;
struct SplayTree{
void Rotate(int x, int f){
int y = pre[x], z = pre[y];
pushdown(x);
pushdown(y);
ch[y][!f] = ch[x][f]; pre[ch[x][f] ] = y;
ch[x][f] = y; pre[y] = x;
pre[x] = z;
if (pre[x]) ch[z][ch[z][1] == y ] = x;
pushup(y);
}
void Splay(int x,int goal){
pushdown(x);
while(pre[x] != goal){
if (pre[pre[x] ] == goal){
Rotate(x, ch[pre[x] ][0] == x);
}
else {
int y = pre[x], z = pre[y];
int f = (ch[z][0] == y);
if (ch[y][f] == x) Rotate(x, !f), Rotate(x, f);
else Rotate(y, f), Rotate(x, f);
}
}
pushup(x);
if (goal == 0) root = x;
}
void RotateTo(int k,int goal){
int x = root;
pushdown(x);
while(sz[ ch[x][0] ] != k){
if (k < sz[ ch[x][0] ]){
x = ch[x][0];
}
else {
k -= (sz[ ch[x][0] ] + 1);
x = ch[x][1];
}
pushdown(x);
}
Splay(x, goal);
}
void clear(){
ch[0][0] = ch[0][1] = pre[0] = sz[0] = 0;
top = 0;
root = n = 0;
val[0] = -inf;
Min[0] = inf;
rev[0] = 0;
add[0] = 0;
NewNode(root, -inf);
NewNode(ch[root][1], inf);
pre[n] = root;
sz[root] = 2;
}
void NewNode(int& x,int c){
if (top) x = pool[--top];
else x = ++n;
ch[x][0] = ch[x][1] = pre[x] = 0;
sz[x] = 1;
val[x] = Min[x] = c;
}
void pushup(int x){
sz[x] = 1 + sz[ch[x][0] ] + sz[ch[x][1] ];
Min[x] = min(val[x] , min(Min[ch[x][0] ] , Min[ch[x][1] ]));
}
void pushdown(int x){
if (rev[x]){
update_rev(ch[x][0]);
update_rev(ch[x][1]);
rev[x] = 0;
}
if (add[x]){
update_add(ch[x][0], add[x]);
update_add(ch[x][1], add[x]);
add[x] = 0;
}
}
void init(int pos, int tot){
clear();
cnt = tot;
RotateTo(pos, 0);
RotateTo(pos + 1, root);
build(ch[ ch[root][1] ][0], 1, tot, ch[root][1]);
pushup(ch[root][1]);
pushup(root);
}
void build(int& x,int l,int r,int f){
if (l > r) return ;
int mid = (l + r) >> 1;
NewNode(x, num[mid]);
build(ch[x][0],l, mid-1, x);
build(ch[x][1], mid+1, r, x);
pre[x] = f;
pushup(x);
}
void update_add(int x,int v){
if (!x) return;
val[x] += v;
Min[x] += v;
add[x] += v;
}
void update_rev(int x){
if (!x) return;
swap(ch[x][0], ch[x][1]);
rev[x] ^= 1;
}
void ADD(int l,int r,int c){
RotateTo(l - 1, 0);
RotateTo(r + 1, root);
int key = ch[ch[root][1] ][0];
update_add(key, c);
pushup(ch[root][1]);
pushup(root);
}
int getmin(int l,int r){
RotateTo(l-1,0);
RotateTo(r+1,root);
int key = ch[ch[root][1] ][0];
return Min[key];
}
void reverse(int l, int r){
RotateTo(l-1, 0);
RotateTo(r + 1, root);
int key = ch[ ch[root][1] ][0];
update_rev(key);
}
void erase(int x){
if (!x) return;
pool[top++] = x;
erase(ch[x][0]);
erase(ch[x][1]);
}
void del(int x){
RotateTo(x-1, 0);
RotateTo(x+1, root);
int key = ch[ ch[root][1] ][0];
ch[ ch[root][1] ][0] = 0;
cnt -= sz[key];
erase(key);
pushup(ch[root][1]);
pushup(root);
}
void insert(int pos, int v){
cnt++;
RotateTo(pos, 0);
RotateTo(pos + 1, root);
num[1] = v;
build(ch[ ch[root][1] ][0], 1, 1, ch[root][1]);
pushup(ch[root][1]);
pushup(root);
}
void revolve(int x, int y, int t){
t %= (y-x+1);
if (t < 0) t = y - x + 1 + t;
if (t == 0) return;
int s2 = y - t + 1, e2 = y;
int s1 = x, e1 = s2 - 1;
RotateTo(s2 - 1, 0);
RotateTo(e2 + 1, root);
int haha = ch[root][1];
RotateTo(e2, haha);
int key = ch[ ch[root][1] ][0];
pre[key] = 0;
ch[ch[root][1] ][0] = 0;
pushup(ch[root][1]);
pushup(root);
RotateTo(s1 - 1, 0);
RotateTo(s1, root);
ch[ch[root][1] ][0] = key;
pre[key] = ch[root][1];
pushup(ch[root][1]);
pushup(root);
}
int root, n, cnt, ct, top;
int ch[maxn][2];
int pre[maxn];
int sz[maxn];
int val[maxn];
int Min[maxn];
int add[maxn];
int pool[maxn];
int rev[maxn];
}spt;
int main(){
int n;
scanf("%d",&n);
for (int i = 1; i <= n; ++i){
scanf("%d", &num[i]);
}
int q;
spt.init(0, n);
scanf("%d", &q);
char op[10];
while(q--){
scanf("%s", op);
if (op[0] == 'A'){
int x, y, d;
scanf("%d %d %d",&x, &y, &d);
spt.ADD(x, y, d);
}
else if (op[0] == 'R'){
if (op[3] == 'E'){
int x, y;
scanf("%d %d",&x, &y);
spt.reverse(x, y);
}
else {
int x, y, t;
scanf("%d %d %d", &x, &y, &t);
spt.revolve(x, y, t);
}
}
else if (op[0] == 'I'){
int x, p;
scanf("%d %d",&x, &p);
spt.insert(x, p);
}
else if (op[0] == 'D'){
int x;
scanf("%d", &x);
spt.del(x);
}
else {
int x, y;
scanf("%d %d", &x, &y);
printf("%d\n", spt.getmin(x, y));
}
}
return 0;
}
SuperMemo
Description Your friend, Jackson is invited to a TV show called SuperMemo in which the participant is told to play a memorizing game. At first, the host tells the participant a sequence of numbers, {A1, A2, ... An}. Then the host performs a series of operations and queries on the sequence which consists:
To make the show more interesting, the participant is granted a chance to turn to someone else that means when Jackson feels difficult in answering a query he may call you for help. You task is to watch the TV show and write a program giving the correct answer to each query in order to assist Jackson whenever he calls. Input The first line contains n (n ≤ 100000). The following n lines describe the sequence. Then follows M (M ≤ 100000), the numbers of operations and queries. The following M lines describe the operations and queries. Output For each "MIN" query, output the correct answer. Sample Input 5 1 2 3 4 5 2 ADD 2 4 1 MIN 4 5 Sample Output 5 Source
POJ Founder Monthly Contest – 2008.04.13, Yao Jinyu
|
[Submit] [Go Back] [Status] [Discuss]