http://acm.hdu.edu.cn/showproblem.php?pid=4453

题意:很多种操作:1、add x,将从光标起的 k2 个数全部加上 x;2、reverse,将从光标起的 k1 个数全部反转;3、insert x,在光标处的后一位插入值为 x 的数;4、delete,删除光标所在位置的数;5、move x,如果x是2,将光标右移,否则将光标左移。6、查询光标所在位置的值。

思路:在ACM中第一次写了6000+bytes的代码,把Splay几乎所有操作都汇集了,是一个很好的入门题目(虽然写了好久好久)。Splay是先插入两个结点,即0号节点下面的root,root的右孩子。Splay是一棵二叉树,满足左儿子比节点小,右儿子比节点大,中序遍历出来的结果就是原来数组的结果。所以我们在插入数组的时候,只要将数组插入到 ch[root][1] 的左孩子 ch[ch[root][1][0] (我的代码中的keytree) 的位置,那么就可以对这些数进行区间操作,并且这些数都是按顺序的。Splay就是利用这样的性质来完成各种操作的。注意因为一开始插入了两个点,所以实际上SplayTree的节点有 n + 2 个,数组中的元素标号从 2 开始到 n + 1。还要注意有 Insert 操作所以数组开大点,有一次TLE是因为这个。

 #include <cstdio>
#include <cstring>
#include <cmath>
#include <cstdlib>
#include <algorithm>
#include <string>
#include <iostream>
#include <stack>
#include <map>
#include <queue>
using namespace std;
#define N 1000010
#define INF 0x3f3f3f3f
#define lson ch[x][0]
#define rson ch[x][1]
#define keytree ch[ch[root][1]][0]
struct SplayTree
{
int fa[N], ch[N][], col[N], rev[N], sz[N], val[N], cnt, root, num[N];
int n, tol, k1, k2; int NewNode(int w, int f, int kind)
{
cnt++;
rev[cnt] = col[cnt] = ch[cnt][] = ch[cnt][] = ;
sz[cnt] = ; val[cnt] = w; fa[cnt] = f;
ch[f][kind] = cnt;
return cnt;
} void PushUp(int x)
{
sz[x] = sz[lson] + sz[rson] + ;
} void PushDown(int x)
{
if(rev[x]) {
swap(lson, rson);
if(lson) rev[lson] ^= ;
if(rson) rev[rson] ^= ;
rev[x] = ;
}
if(col[x]) {
if(lson) {
col[lson] += col[x];
val[lson] += col[x];
}
if(rson) {
col[rson] += col[x];
val[rson] += col[x];
}
col[x] = ;
}
} void Build(int l, int r, int &x, int f, int kind)
{
if(r < l) return ;
int m = (l + r) >> ;
x = NewNode(num[m], f, kind);
Build(l, m - , ch[x][], x, );
Build(m + , r, ch[x][], x, );
PushUp(x);
} void Init() // 初始化
{
cnt = root = ;
col[] = fa[] = rev[] = val[] = ch[][] = ch[][] = sz[] = ;
root = NewNode(, , ); // 先开两个节点,然后把数组元素放进 keytree 的位置
ch[root][] = NewNode(, root, );
sz[root] = ;
Build(, n, keytree, ch[root][], );
PushUp(ch[root][]); PushUp(root);
} void Rotate(int x, int kind)
{
int y = fa[x], z = fa[y];
PushDown(y); PushDown(x);
ch[y][!kind] = ch[x][kind];
if(ch[x][kind]) fa[ch[x][kind]] = y;
fa[y] = x; fa[x] = z;
if(z) {
if(ch[z][] == y) ch[z][] = x;
else ch[z][] = x;
}
ch[x][kind] = y;
PushUp(y);
} void Splay(int x, int goal)
{
while(fa[x] != goal) {
int y = fa[x], z = fa[y];
PushDown(z); PushDown(y); PushDown(x);
int kind1 = ch[y][] == x;
int kind2 = ch[z][] == y;
if(z == goal) {
Rotate(x, kind1);
} else {
if(kind1 == kind2) {
Rotate(y, kind2);
} else {
Rotate(x, kind1);
}
Rotate(x, kind2);
}
// printf("%d, %d, %d\n", x, fa[x], goal);
}
PushUp(x);
if(goal == ) root = x;
} void RTO(int k, int goal) // 将第k个元素旋转到0号节点下面
{
int x = root;
PushDown(x);
while() {
if(k <= sz[lson]) x = lson;
else if(k == sz[lson] + ) break;
else {
k -= sz[lson] + ;
x = rson;
}
PushDown(x);
}
Splay(x, goal);
} void Insert(int val, int index)
{
RTO(index, ); RTO(index + , root);
keytree = NewNode(val, ch[root][], );
PushUp(ch[root][]); PushUp(root);
// Splay(keytree, 0);
} int Delete(bool kind)
{
int w;
if(kind) {
RTO(, ); RTO(, root);
w = val[keytree];
keytree = ;
} else {
int ed = sz[root];
RTO(ed - , ); RTO(ed, root);
w = val[keytree];
keytree = ;
}
PushUp(ch[root][]); PushUp(root);
// Splay(root, 0);
return w;
} void Move(int kind) // 光标移动, 如果向左移动就删除最后的元素插到最前面, 向右移动反之
{
int w;
if(kind == ) {
w = Delete();
Insert(w, );
} else {
w = Delete();
Insert(w, sz[root] - );
}
} void Reverse()
{
RTO(, );
// Debug(root);
RTO(k1 + , root);
// puts("----------------");
// Debug(root);
// puts("----------------");
rev[keytree] ^= ;
// swap(ch[keytree][0], ch[keytree][1]);
PushUp(ch[root][]); PushUp(root);
} void Add(int w)
{
RTO(, ); RTO(k2 + , root);
// printf("add\n");
col[keytree] += w;
val[keytree] += w;
PushUp(ch[root][]); PushUp(root);
} int Query() // 查询操作将要查询的数移动到根节点直接查询
{
RTO(, );
// printf("%d\n", root);
return val[root];
} void Debug(int x)
{
if(lson) Debug(lson);
printf("%d : %d, %d, %d, %d\n", val[x], val[lson], val[rson], lson, rson);
if(rson) Debug(rson);
}
}splay; int main()
{
int q, cas = ;
while(~scanf("%d%d%d%d", &splay.n, &q, &splay.k1, &splay.k2), splay.n + q + splay.k1 + splay.k2) {
for(int i = ; i <= splay.n; i++) scanf("%d", &splay.num[i]);
splay.Init();
char s[];
printf("Case #%d:\n", cas++);
for(int i = ; i <= q; i++) {
scanf("%s", s);
int x;
if(s[] == 'q') printf("%d\n", splay.Query());
else if(s[] == 'a') {
scanf("%d", &x);
splay.Add(x);
} else if(s[] == 'r') {
splay.Reverse();
} else if(s[] == 'i') {
scanf("%d", &x);
splay.Insert(x, );
} else if(s[] == 'd') {
splay.Delete();
} else if(s[] == 'm') {
scanf("%d", &x);
splay.Move(x);
}
// splay.Debug(splay.root);
}
}
return ;
}

HDU 4453:Looploop(Splay各种操作)的更多相关文章

  1. HDU 4453 Looploop (伸展树splay tree)

    Looploop Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Su ...

  2. hdu 4453 splay

    Looploop Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total S ...

  3. hdu 2871 线段树(各种操作)

    Memory Control Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) T ...

  4. BZOJ1500: [NOI2005]维修数列 [splay序列操作]【学习笔记】

    以前写过这道题了,但我把以前的内容删掉了,因为现在感觉没法看 重写! 题意: 维护一个数列,支持插入一段数,删除一段数,修改一段数,翻转一段数,查询区间和,区间最大子序列 splay序列操作裸题 需要 ...

  5. P2596 [ZJOI2006]书架 && Splay 区间操作(三)

    P2596 [ZJOI2006]书架 题目描述 小T有一个很大的书柜.这个书柜的构造有些独特,即书柜里的书是从上至下堆放成一列.她用1到n的正整数给每本书都编了号. 小T在看书的时候,每次取出一本书, ...

  6. HDU 1754 I Hate It (Splay 区间操作)

    题目大意 维护一个序列,支持两种操作 操作一:将第x个元素的值修改为y 操作二:询问区间[x,y]内的元素的最大值 解题分析 splay的区间操作,事先加入两个编号最小和最大的点防止操作越界. 具体的 ...

  7. hdu 2475 BOX (splay)

    版权声明:本文为博主原创文章,未经博主允许不得转载. hdu 2475 Splay树是一种神奇的东西... 题意: 有一些箱子,要么放在地上,要么放在某个箱子里面 . 现在有两种操作: (1) MOV ...

  8. 「BZOJ1251」序列终结者 (splay 区间操作)

    题面: 1251: 序列终结者 Time Limit: 20 Sec  Memory Limit: 162 MBSubmit: 5367  Solved: 2323[Submit][Status][D ...

  9. P2042 [NOI2005]维护数列 && Splay区间操作(四)

    到这里 \(A\) 了这题, \(Splay\) 就能算入好门了吧. 今天是个特殊的日子, \(NOI\) 出成绩, 大佬 \(Cu\) 不敢相信这一切这么快, 一下子机房就只剩我和 \(zrs\) ...

随机推荐

  1. Java学习——变量类型

    Java有3类变量 局部变量 成员变量(实例变量) 类变量(静态变量) 局部变量 局部变量声明在方法.构造方法或者语句块中: 局部变量在方法.构造方法.或者语句块被执行的时候创建,当它们执行完成后,变 ...

  2. 在centos安装docker

    关闭防火墙 iptables -L systemctl disable firewalld.service systemctl stop firewalld.service 配置代理太麻烦了,建议使用 ...

  3. NSString

    // —————————NSString // NSString //1.初始化:直接字符串.格式化字符串.文件读取内容初始化 NSString *str1 = @"hello world! ...

  4. 【转】Java多线程编程中易混淆的3个关键字( volatile、ThreadLocal、synchronized)总结

    概述 最近在看<ThinKing In Java>,看到多线程章节时觉得有一些概念比较容易混淆有必要总结一下,虽然都不是新的东西,不过还是蛮重要,很基本的,在开发或阅读源码中经常会遇到,在 ...

  5. linux:ACL权限

    ACL权限是为了防止权限不够用的情况,一般的权限有所有者.所属组.其他人这三种,当这三种满足不了我们的需求的时候就可以使用ACL权限: 比如:一个网络老师,给一个班的学员上课,他在linux的根目录下 ...

  6. [翻译]java nio 概述

    原文地址:http://tutorials.jenkov.com/java-nio/overview.html java NIO 包含一下核心内容: Channels Buffers Selector ...

  7. Swift游戏实战-跑酷熊猫 11 欢迎进入物理世界

    物理模拟是一个奇妙的事情,以此著名的游戏有愤怒的小鸟.我们在这节将会一起来了解如何设置重力,设置物理包围体,碰撞的检测. 要点: 设置物理检测的代理: 让主场景遵循SKPhysicsContactDe ...

  8. nyist 506 洗澡

    http://acm.nyist.net/JudgeOnline/problem.php?pid=506 洗澡 时间限制:1000 ms  |  内存限制:65535 KB 难度:1   描述 Mos ...

  9. paper 43 :ENDNOTE下载及使用方法简介

    转载来源:http://blog.sciencenet.cn/blog-484734-367968.html 软件下载来源: EndNote v9.0 Final 正式版:http://www.ttd ...

  10. java 项目打包流程速记

    1.与资源库同步 2.[解决冲突] --可能没有这一步 3.合并标记 4.清除一下项目-- clean 5.打包: run As -->Maven install 6.去服务备份原包,下载服务 ...