您的位置:首页 > 其它

POJ 3580 SuperMemo (Splay)

2017-10-12 16:52 459 查看
思路:

区间的一系列操作, 还有翻转什么的,显然Splay

主要说一下 那个循环右移的操作吧

次数先对总长度取模, 因为相当于有循环节。

然后  这个操作 相当于 把一个区间分成两个子区间, 把后面挪到前面。

假设两个区间是 [s1, e1]和 [s2, e2]

那么先把s2-1 转到根, e2+1 转到根的下面, 将e2转到e2+1的下面,将 e2+1的左子树 切下来。

这样就把后一个区间拿出来了,  同样的操作  将s1-1转到根, s1 转到根的下面, 插到 s1左子树即可。

#include <cstdio>
#include <cstring>
#include <algorithm>
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
= 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

Time Limit: 5000MS Memory Limit: 65536K
Total Submissions: 16777 Accepted: 5288
Case Time Limit: 2000MS
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:

ADD x y D: Add D to each number in sub-sequence {Ax ... Ay}. For example, performing "ADD 2 4 1" on {1, 2, 3, 4, 5} results in {1, 3, 4, 5, 5}
REVERSE x y: reverse the sub-sequence {Ax ... Ay}. For example, performing "REVERSE 2 4" on {1, 2, 3, 4, 5} results in {1, 4, 3, 2, 5}
REVOLVE x y T: rotate sub-sequence {Ax ... Ay} T times. For example, performing "REVOLVE 2 4 2" on {1, 2, 3, 4, 5} results in {1, 3, 4, 2, 5}
INSERT x P: insert P after Ax. For example, performing "INSERT 2 4" on {1, 2, 3, 4, 5} results in {1, 2, 4, 3, 4, 5}
DELETE x: delete Ax. For example, performing "DELETE 2" on {1, 2, 3, 4, 5} results in {1, 3, 4, 5}
MIN x y: query the participant what is the minimum number in sub-sequence {Ax ... Ay}. For example, the correct answer to "MIN 2 4" on {1, 2, 3, 4, 5} is 2
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]
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: