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树),是二叉排序树的一种.[两个月之前写过,今天突然想写个博客...] 伸展树和一般的二叉排序树不同的是,在每次执行完插入.查询.删除等操作后,都会自动平衡这棵树.(说是自动,也就是 ...
随机推荐
- mac 安装 navicat premium11.2.1400 破解版
前言: 在 Mac 系统下 安装 navicat for mysql 时,遇到注册码的问题,适用了很多破解下载,都没有成功,现找到一篇特此记录下. Mac 下一款实用的数据库管理工具--Navicat ...
- BEE网站
http://www.bee-framework.com/ http://syxiaqj.github.io/2014/02/28/bee-learning-1/#0-tsina-1-24637-39 ...
- Linux虚拟地址空间布局以及进程栈和线程栈总结
原文链接:http://blog.csdn.net/freeelinux/article/details/53782986[侵删] 本文转自多个博客,以及最后有我的总结.我没有单独从头到尾写一个总结的 ...
- app:compileDebugNdk,NDK
Error:Execution failed for task ':app:compileDebugNdk'. > Error: Your project contains C++ files ...
- ppt提取图片,视频文件
1,将视频另存为htm格式,然后会生成文件夹,里面就有. 2,如果没法生成htm格式,可以生成odp格式,压缩文件,用解压缩软件查看odp文件,就能看到. 3,pptx直接修改后缀为rar或者zip, ...
- 在Ubuntu/Centos使用 Let's Encrypt 证书部署 HTTPS的方法
certbot地址 apache服务器(ubuntu环境): 1.获取软件包: $ sudo apt-get update $ sudo apt-get install software-proper ...
- 几何【P2313】 [HNOI2005]汤姆的游戏
顾z 你没有发现两个字里的blog都不一样嘛 qwq 题目描述--->p2313 [HNOI]汤姆的游戏 分析 说不上是分析. 数据范围给出来,这题明显暴力啊emmm. 个人认为的坑点. 这题不 ...
- Nginx的server为0.0.0.0/0.0.0.1的作用?
看到kong默认的代理和后台server 都是0.0.0.0,代理到上游的服务器proxy_pass $upstream_scheme://kong_upstream;配置如下, upstream k ...
- 关于MapControl和PageLayout地图同步的问题
按照ArcMap的处理方式,地图和制图是分两个页面的,他们之间通过共享同一个Map对象来实现地图同步,具体做法就是在PageLayoutControl的PageLayoutReplaced事件发生时, ...
- Android Linux内核编译
平台: Wind7_64 + Ubuntu12_04_64 + VMware 这里以Android5.0为例: Android5.0 可以到这里下载:115网盘礼包码:5lbd7crtk1wzhttp ...