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. linux内核编译相关

    参考:http://www.arm.linux.org.uk/docs/kerncomp.php 一. 内核编译1) linux 2.4make clean/make mrpropermake dep ...

  2. mysql centeros 安装

    http://www.cnblogs.com/xiaoluo501395377/archive/2013/04/07/3003278.html linux mysql允许远程连接 1.登录数据库:my ...

  3. Java Collections的排序之二

    package test.list; import java.util.ArrayList; import java.util.Collections; import java.util.HashSe ...

  4. Java基础之写文件——创建通道并且写文件(TryChannel)

    控制台程序,创建一个文件并且使用通道将一些文本写入到这个文件中. import static java.nio.file.StandardOpenOption.*; import java.nio.c ...

  5. Swift实战-豆瓣电台(六)视图跳转,传参及回跳

    youku观看地址:http://v.youku.com/v_show/id_XNzMxMzQ3MDcy.html 要点 在ChannelController里面声明一个代理 这个代理遵循我们自定义的 ...

  6. Lintcode: Single Number III

    Given 2*n + 2 numbers, every numbers occurs twice except two, find them. Example Given [1,2,2,3,4,4, ...

  7. Lintcode: Merge Sorted Array II

    Merge two given sorted integer array A and B into a new sorted integer array. Example A=[1,2,3,4] B= ...

  8. poj 1475 || zoj 249 Pushing Boxes

    http://poj.org/problem?id=1475 http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=249 Pushin ...

  9. DataBase: LeetCode

    Combine Two Tables # Write your MySQL query statement below Select p.FirstName, p.LastName, a.City, ...

  10. yii2封装一个类控制div宽度,高度

    1.首先,封装一个类,放在文件夹vendor下,命名为articls.php. <?phpclass Articles{ //测试    function add()    {        r ...