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树),是二叉排序树的一种.[两个月之前写过,今天突然想写个博客...] 伸展树和一般的二叉排序树不同的是,在每次执行完插入.查询.删除等操作后,都会自动平衡这棵树.(说是自动,也就是 ...
随机推荐
- Topcoder SRM 606 div1题解
打卡! Easy(250pts): 题目大意:一个人心中想了一个数,另一个人进行了n次猜测,每一次第一个人都会告诉他实际的数和猜测的数的差的绝对值是多少,现在告诉你所有的猜测和所有的差,要求你判断心中 ...
- EF4学习链接
原文发布时间为:2011-09-23 -- 来源于本人的百度文章 [由搬家工具导入] 1.Fluent API 的方式定义与数据库映射 2.利用特性实现与数据库的映射 3.EF的一些公约的介绍 4.E ...
- 推荐几个好用的PHP集成开发环境
(转自:http://blog.sina.com.cn/s/blog_5bd6b45101011bu2.html ) 分类: PHP PHP新手在准备正式开始写PHP代码的时候,不幸的是被PHP的开发 ...
- Linux内核实践之序列文件【转】
转自:http://blog.csdn.net/bullbat/article/details/7407194 版权声明:本文为博主原创文章,未经博主允许不得转载. 作者:bullbat seq_fi ...
- Linux学习总结—缺页中断和交换技术【转】
三.Linux缺页中断处理 转自:http://blog.csdn.net/cxylaf/article/details/1626534 1.请求调页中断: 进程线性地址空间里的页面不必常驻内存,例如 ...
- js比对一维数组全等的算法
//辅助方法1,返回某个值在数组中的位置 Array.prototype.indexOf = function (e) { for (var i = 0, l = this.length; i < ...
- 配置和读取INI
#define MAX_FILE_PATH 260 void CControlDlg::OnBnClickedBtnGamepath() { // TODO: 在此添加控件通知处理程序代码 CFile ...
- Mysql优化的方法
一.表的优化: 1: 定长与变长分离 如 time.手机号等,每一单元值占的字节是固定的. 核心且常用字段,宜建成定长,放在一张表,查询速度会很快 而varchar, text,blob,这种变长字段 ...
- [BZOJ1455]罗马游戏 左偏树+并查集
1455: 罗马游戏 Time Limit: 5 Sec Memory Limit: 64 MBSubmit: 2285 Solved: 994[Submit][Status][Discuss] ...
- vi / vim 设置
一.vi下方向键输入后,出现ABCD,解决方法: 在vi中输入:set nocp 按回车即可. 二.设置TAB缩进4个空格: 为了vim更好的支持python写代码,修改tab默认4个空格有两种设置方 ...