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树),是二叉排序树的一种.[两个月之前写过,今天突然想写个博客...] 伸展树和一般的二叉排序树不同的是,在每次执行完插入.查询.删除等操作后,都会自动平衡这棵树.(说是自动,也就是 ...
随机推荐
- Jsoup 标签选择器 选择img标签中src的值
package com.enation.newtest; import java.io.BufferedReader; import java.io.File; import java.io.File ...
- php 字符串重要函数
1.chop() 从字符串右端移除字符 chop(string,charlist) $str="hello world~"; echo chop($str,"ld~&qu ...
- Spring数据访问之JdbcTemplate
Spring数据访问之JdbcTemplate 使用JdbcTemplate的基本操作步骤 1.引jar包
- [ CodeVS冲杯之路 ] P1501
不充钱,你怎么AC? 题目:http://codevs.cn/problem/1501/ 水题一道 直接dfs,记录上当前深度,到了叶子节点就更新答案,并且每个节点将当前深度的计数+1,答案即为ma ...
- 免费的二维码发布平台 http://zhifubao.masao.top:8282/assets/index.html
http://zhifubao.masao.top:8282/assets/index.html
- 杭电oj2031、2033、2070、2071、2075、2089、2090、2092、2096-2099
2031 进制转换 #include<stdio.h> #include<string.h> int main(){ int n,i,r,x,j,flag; ]; while ...
- windows实时监测热插拔设备的变化2
//动态监测设备插拔 #include <Dbt.h> BEGIN_MESSAGE_MAP(ParticipateMeeting, CDialogEx) ON_WM_DEVICECHANG ...
- python 查询数据
查找课程不及格学生最多的前5名老师的id 表:student 字段名 类型 是否为空 主键 描述 StdID int 否 是 学生ID StdName varchar(100) 否 学生姓名 Gend ...
- ef code first commad
PM> enable-migrations 已在项目“EasyWeChat.Data”中启用迁移.若要覆盖现有迁移配置,请使用 -Force 参数. PM> add-migration 位 ...
- (3)C#基本语法
1.C#标识符 标识符是用来识别类.变量.函数或任何其它用户定义的项目. 在 C# 中,类的命名必须遵循如下基本规则: 标识符必须以字母开头,后面可以跟一系列的字母.数字.下划线.标识符中的第一个字符 ...