Splay树(多操作)——POJ 3580 SuperMemo
相应POJ题目:点击打开链接
Time Limit: 5000MS | Memory Limit: 65536K | |
Total Submissions: 11309 | Accepted: 3545 | |
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
题意:
对n个数有6种操作:
1)增值:ADD x y D:区间 [x, y] 的全部值添加D
2)翻转:REVERSE x y:把区间 [x, y] 翻转
3)旋转:REVOLVE x y T:对区间 [x, y]顺时针(T > 0)或逆时针(T < 0)旋转T次
4)插入:INSERT x P:在A[x]后面插入P
5)删除:DELETE x:删除A[x]
6)最值:MIN x y:求区间 [x, y] 内的最小值
思路:
Splay树综合操作;须要注意的地方有:
1、Push_down()。Push_up()的写法。应该在什么地方调用
2、旋转操作的T能够是负数
3、旋转事实上就是把区间的后一段取下放到前面或着把前一段取下放到后面,不难想明确
#include <cstdio>
#include <cstdlib>
#include <string>
#include <algorithm>
#include <string.h>
#include <cmath>
#include <iostream>
#define MIN(x, y) ((x)<(y)?(x):(y))
const int MAXN = 100100;
using namespace std;
typedef int Type; typedef struct TREE
{
Type val, add, min_v;
bool flag;
TREE *fa, *l, *r;
int sz; //以该结点为根的树的总结点数
}Tree; inline void Swap(int &a, int &b)
{
int t = a;
a = b;
b = t;
} class SplayTree
{
public:
SplayTree()
{
rt = NULL;
inf = 1000000000;
} void Push_down(Tree *T)
{
if(NULL == T) return;
if(T->add){
if(T->l){
T->l->val += T->add;
T->l->add += T->add;
T->l->min_v += T->add;
}
if(T->r){
T->r->val += T->add;
T->r->add += T->add;
T->r->min_v += T->add;
}
T->add = 0;
}
if(T->flag){
tmp = T->l;
T->l = T->r;
T->r = tmp;
if(T->l) T->l->flag ^= 1;
if(T->r) T->r->flag ^= 1;
T->flag = 0;
}
} void Push_up(Tree *T)
{
T->sz = (T->l ? T->l->sz : 0) + (T->r ? T->r->sz : 0) + 1;
if(T->l && T->r) T->min_v = MIN(T->val, MIN(T->l->min_v, T->r->min_v));
else if(T->l) T->min_v = MIN(T->l->min_v, T->val);
else if(T->r) T->min_v = MIN(T->r->min_v, T->val);
else T->min_v = T->val; //切记! } void NewNode(Tree *pre, Tree *&T, Type v)
{
T = (Tree *)malloc(sizeof(Tree));
T->val = T->min_v = v;
T->add = 0;
T->flag = 0;
T->sz = 1;
T->fa = pre;
T->l = T->r = NULL;
} void MakeTree(Tree *pre, Tree *&T, int x, int y)
{
if(x > y) return;
int mid = ((x + y)>>1);
NewNode(pre, T, c[mid]);
MakeTree(T, T->l, x, mid - 1);
MakeTree(T, T->r, mid + 1 , y);
Push_up(T);
} void Init(int n)
{
int i;
for(i = 1; i <= n; i++)
scanf("%d", c + i);
NewNode(NULL, rt, -inf);
NewNode(rt, rt->r, inf);
rt->sz = 2;
MakeTree(rt->r, rt->r->l, 1, n);
Push_up(rt->r);
Push_up(rt);
} void R_rotate(Tree *x)
{
Tree *y = x->fa;
Tree *z = y->fa;
Tree *k = x->r;
y->l = k;
x->r = y;
if(z){
if(y == z->l) z->l = x;
else z->r = x;
}
if(k) k->fa = y;
y->fa = x;
x->fa = z;
Push_up(y);
} void L_rotate(Tree *x)
{
Tree *y = x->fa;
Tree *z = y->fa;
Tree *k = x->l;
y->r = k;
x->l = y;
if(z){
if(y == z->r) z->r = x;
else z->l = x;
}
if(k) k->fa = y;
y->fa = x;
x->fa = z;
Push_up(y);
} //寻找第x个数的结点
Tree *FindTag(int x)
{
x++;
if(NULL == rt) return NULL;
Tree *p;
p = rt;
Push_down(p);
Type sum = (p->l ? p->l->sz : 0) + 1;
while(sum != x)
{
if(sum < x){
p = p->r;
x -= sum;
}
else p = p->l;
if(NULL == p) break;
Push_down(p);
sum = (p->l ? p->l->sz : 0) + 1;
}
return p;
} void Splay(Tree *X, Tree *&T)
{
Tree *p, *end;
end = T->fa;
while(X->fa != end)
{
p = X->fa;
if(end == p->fa){ //p是根结点
if(X == p->l) R_rotate(X);
else L_rotate(X);
break;
}
//p不是根结点
if(X == p->l){
if(p == p->fa->l){
R_rotate(p); //LL
R_rotate(X); //LL
}
else{
R_rotate(X); //RL
L_rotate(X);
}
}
else{
if(p == p->fa->r){ //RR
L_rotate(p);
L_rotate(X);
}
else{ //LR
L_rotate(X);
R_rotate(X);
}
}
}
T = X;
Push_up(T);
} void Get_interval(int x, int y) //把第x个数转到根,把第y个数转到根的右儿子
{
tmp = FindTag(x);
Splay(tmp, rt);
tmp = FindTag(y);
Splay(tmp, rt->r);
} void Add(int x, int y, int d)
{
if(x > y) Swap(x, y);
Get_interval(x - 1, y + 1);
rt->r->l->add += d;
rt->r->l->val += d;
rt->r->l->min_v += d;
Push_up(rt->r);
Push_up(rt);
} void Reverse(int x, int y)
{
if(x > y) Swap(x, y);
Get_interval(x - 1, y + 1);
rt->r->l->flag ^= 1;
} void Revolve(int x, int y, int t)
{
if(x > y) Swap(x, y);
t = t % (y - x + 1); //取模
if(t < 0) t += (y - x + 1);
if(0 == t) return;
Get_interval(y - t, y + 1);
Tree *sub = rt->r->l;
rt->r->l = NULL;
Push_up(rt->r);
Push_up(rt);
Get_interval(x - 1, x);
rt->r->l = sub;
sub->fa = rt->r;
Push_up(rt->r);
Push_up(rt);
} void Insert(int pos, int v)
{
Get_interval(pos, pos + 1);
NewNode(rt->r, rt->r->l, v);
Push_up(rt->r);
Push_up(rt);
} void Delete(int pos)
{
Get_interval(pos - 1, pos + 1);
free(rt->r->l);
rt->r->l = NULL;
Push_up(rt->r);
Push_up(rt);
} void Min(int x, int y)
{
if(x > y) Swap(x, y);
Get_interval(x - 1, y + 1);
Push_down(rt->r->l);
printf("%d\n", rt->r->l->min_v);
} void Free()
{
FreeTree(rt);
} void FreeTree(Tree *T)
{
if(NULL == T) return;
FreeTree(T->l);
FreeTree(T->r);
free(T);
} private:
Type c[MAXN], inf;
Tree *rt, *tmp;
}; SplayTree spl; int main()
{
//freopen("in.txt","r",stdin);
int n, m, x, y, z;
char ord[10];
while(scanf("%d", &n) == 1)
{
spl.Init(n);
scanf("%d", &m);
while(m--)
{
scanf("%s", ord);
if(!strcmp("ADD", ord)){
scanf("%d%d%d", &x, &y, &z);
spl.Add(x, y, z);
}
if(!strcmp("REVERSE", ord)){
scanf("%d%d", &x, &y);
spl.Reverse(x, y);
}
if(!strcmp("REVOLVE", ord)){
scanf("%d%d%d", &x, &y, &z);
spl.Revolve(x, y, z);
}
if(!strcmp("INSERT", ord)){
scanf("%d%d", &x, &y);
spl.Insert(x, y);
}
if(!strcmp("DELETE", ord)){
scanf("%d", &x);
spl.Delete(x);
}
if(!strcmp("MIN", ord)){
scanf("%d%d", &x, &y);
spl.Min(x, y);
}
}
spl.Free();
}
return 0;
}
Splay树(多操作)——POJ 3580 SuperMemo的更多相关文章
- 平衡树(Splay):Splaytree POJ 3580 SuperMemo
SuperMemo Description Your friend, Jackson is invited to a TV show called SuperMemo in which ...
- poj 3580 SuperMemo
题目连接 http://poj.org/problem?id=3580 SuperMemo Description Your friend, Jackson is invited to a TV sh ...
- POJ 3580 - SuperMemo - [伸展树splay]
题目链接:http://poj.org/problem?id=3580 Your friend, Jackson is invited to a TV show called SuperMemo in ...
- POJ 3580 SuperMemo (splay tree)
SuperMemo Time Limit: 5000MS Memory Limit: 65536K Total Submissions: 6841 Accepted: 2268 Case Ti ...
- POJ 3580 SuperMemo 伸展树
题意: 维护一个序列,支持如下几种操作: ADD x y D:将区间\([x,y]\)的数加上\(D\) REVERSE x y:翻转区间\([x,y]\) REVOLVE x y T:将区间\([x ...
- Splay树简单操作
前几天刚刚自学了一下splay,发现思路真简单实现起来好麻烦 先贴一下头文件 # include <stdio.h> # include <stdlib.h> # includ ...
- 线段树(区间操作) POJ 3325 Help with Intervals
题目传送门 题意:四种集合的操作,对应区间的01,问最后存在集合存在的区间. 分析:U T [l, r]填充1; I T [0, l), (r, N]填充0; D T [l, r]填充0; C T[0 ...
- POJ 3580 SuperMemo (FHQ_Treap)
题意:让你维护一个序列,支持以下6种操作: ADD x y d: 第x个数到第y个数加d . REVERSE x y : 将区间[x,y]中的数翻转 . REVOLVE x y t :将区间[x,y] ...
- 伸展树(Splay树)的简要操作
伸展树(splay树),是二叉排序树的一种.[两个月之前写过,今天突然想写个博客...] 伸展树和一般的二叉排序树不同的是,在每次执行完插入.查询.删除等操作后,都会自动平衡这棵树.(说是自动,也就是 ...
随机推荐
- 关闭vscode打开新文件自动关闭预览文件功能
经常碰到这个问题,我打开文件就是有用的,每次给我自动关闭了我还得去打开. 当然这个问题可以双击文件,接触那个文件的预览状态就可以解决了.不过还有一个更懒的方法,直接修改vscode配置就好了. // ...
- js j将数字每三位用逗号隔开的方法
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...
- Hidden (NOIP模拟赛)(字符串模拟QAQ)
原题传送门 神奇的题目诶 原来以为字符串比较一定要O(NlogN) 结果发现可以均摊O(N) 首先我们来讲一讲原理 我们有3个指针i,j,k i=0,j=1,k=0 一开始我们不断对k+1直到找到ch ...
- (10)ubuntu内核源码树
ubuntu内核源码树目录: root@ubuntu:/lib/modules/3.13.0-32-generic/build#
- vue-cli 3.0脚手架与vux的配合使用
在最近的项目中,引用了vux,在可拓展性以及复用性,都算是比较优秀的框架了.但是美中不足的是对于vux在对于vue-cli3.0的跟进还没有同步 需要自己做下修改,同比 有赞的vant 以及 ivie ...
- mysq 中 information_schema 库
information_schema这个库,这个在mysql安装时就有了,提供了访问数据库元数据的方式.那什么是元数据库呢?元数据是关于数据的数据,如数据库名或表名,列的数据类型,或访问权限等.有些时 ...
- 【linux高级程序设计】(第十二章)Linux多线程编程 3
条件变量通信机制 条件变量必须配合互斥锁一起实现对资源的互斥访问 使用方法: int pthread_cond_init (pthread_cond_t *__restrict __cond, __c ...
- ubuntu 更换系统源和pip源
1 . 备份 cd /etc/apt sudo cp sources-list sources-list.bak 2 . 编辑 这里用了阿里云的源 sudo vi sources-list 将文件内容 ...
- sysbench(mysql测试工具 )
目录 一.基准测试简介 1.什么是基准测试 2.基准测试的作用 3.基准测试的指标 4.基准测试的分类 二.sysbench 1.sysbench简介 2.sysbench安装 3.sysbench语 ...
- 关于yii2 的db log 日志 错误处理errorHandler
log 通过配置Web.config来完成 1 数据库增加 ‘前缀_log’表 2 配置Web.config 'bootstrap' => ['log'], 'components' => ...