hdu4453-Looploop(伸展树)
题目有很多图,不好粘贴。。。。。
题意:给出N个数和K1,K2的值,最开始指针指向第一个数,有6种操作
add x : 给前K2个数都增加x
reverse : 翻转前K1个数
insert x : 在所指的数右边(顺时针)插入一个数
delete x : 删除指针所指的这个数,并且指针向右移(顺时针)
move x : x=1则指向向左移(逆时针),为2向右移(顺时针)
query : 输出指针所指的数
解析:这题涉及到插入删除,和给一段区间加值,线段树不能增加删除,链表的话又不能快速的给一段区间加数,所以只能用伸展树了。伸展树支持的操作很多,既有线段树的特性也有链表的特性。但是写起来复杂,所以一般题目如果能用常用的数据结构解决的就不要用伸展树了。我不具体介绍伸展树,自己下去多学学再看这题会容易许多。
源代码
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
using namespace std;
const int INF=1e9+;
const int maxn=;
int A[maxn],cnt; //A数组保存数,cnt是节点标号,我是用数组模拟的
struct treap
{
treap* son[]; //左右儿子
int v,s,add,lazy; //v是值,s是大小,add是懒惰标记增加的值,lazy是懒惰标记是否需要翻转
treap(){ v=s=add=lazy=; son[]=son[]=NULL; }
treap(int nv);
int rk(){ return son[]->s+; } //排名,第几个数
int cmp(int k) //比较,如果相等返回-1,小于返回0,大于1
{
if(k==rk()) return -;
return k<rk()?:;
}
void pushup(){ s=son[]->s+son[]->s+; } //更新大小
void pushdown() //处理懒惰标记
{
if(lazy)
{
swap(son[],son[]);
son[]->lazy^=;
son[]->lazy^=;
lazy=;
}
if(add)
{
v+=add;
son[]->add+=add;
son[]->add+=add;
add=;
}
}
}null,tr[maxn];
treap::treap(int nv)
{
v=nv;
s=;
add=lazy=;
son[]=son[]=&null;
}
treap* NewNode(int x)
{
tr[cnt]=treap(x);
return tr+cnt++;
}
struct splaytree
{
int Size;
treap* root;
splaytree(){ Size=; root=&null; }
void Rotate(treap* &t,int d) //翻转操作
{
t->pushdown();
treap* p=t->son[d^];
p->pushdown();
t->son[d^]=p->son[d];
p->son[d]=t;
t->pushup();
t=p;
t->pushup();
}
void Splay(treap* &t,int k) //将第k大的节点伸展到根
{
t->pushdown();
int d=t->cmp(k);
if(d!=-)
{
if(d) Splay(t->son[d],k- t->rk());
else Splay(t->son[d],k);
Rotate(t,d^);
}
}
void Build(treap* &t,int le,int ri) //将N个数建成一棵树
{
if(le>ri) return;
int mid=(le+ri)/;
t=NewNode(A[mid]);
Build(t->son[],le,mid-);
Build(t->son[],mid+,ri);
t->pushup();
}
void Add(treap* &t,int k,int a) //加值
{
Splay(t,k);
t->v+=a;
t->son[]->add+=a;
}
void Reverse(treap* &t,int k) //翻转
{
Splay(t,k);
treap* p=t->son[];
t->son[]=&null;
t->pushup();
t->lazy=;
t->pushdown();
Splay(t,k);
t->son[]=p;
t->pushup();
}
void Insert(treap* &t,int x) //插入
{
Splay(t,);
treap* p=NewNode(x);
p->son[]=t->son[];
p->pushup();
t->son[]=p;
t->pushup();
Size++;
}
void Remove(treap* &t) 删除
{
Splay(t,);
treap* next=t->son[];
t=next;
t->pushdown();
Size--;
}
void Move(treap* &t,int x) //移动
{
if(x==)
{
Splay(t,Size);
treap* p=t->son[];
t->son[]=&null;
p->pushdown();
Splay(p,);
t->son[]=p;
t->pushup();
}
else
{
Splay(t,);
treap* p=t->son[];
t->son[]=&null;
p->pushdown();
Splay(p,Size-);
t->son[]=p;
t->pushup();
}
}
};
int N,M,K1,K2;
int main()
{
int Case=;
while(scanf("%d%d%d%d",&N,&M,&K1,&K2)!=EOF)
{
if(!N&&!M&&!K1&&!K2) break;
for(int i=;i<=N;i++) scanf("%d",&A[i]);
cnt=;
splaytree spt;
spt.Build(spt.root,,N);
spt.Size=N;
printf("Case #%d:\n",++Case);
while(M--)
{
char op[];
int x;
scanf("%s",op);
if(strcmp(op,"add")==)
{
scanf("%d",&x);
spt.Add(spt.root,K2,x);
}
else if(strcmp(op,"reverse")==) spt.Reverse(spt.root,K1);
else if(strcmp(op,"insert")==)
{
scanf("%d",&x);
spt.Insert(spt.root,x);
}
else if(strcmp(op,"delete")==) spt.Remove(spt.root);
else if(strcmp(op,"move")==)
{
scanf("%d",&x);
spt.Move(spt.root,x);
}
else
{
spt.Splay(spt.root,);
printf("%d\n",spt.root->v);
}
}
}
return ;
}
hdu4453-Looploop(伸展树)的更多相关文章
- Splay伸展树学习笔记
Splay伸展树 有篇Splay入门必看文章 —— CSDN链接 经典引文 空间效率:O(n) 时间效率:O(log n)插入.查找.删除 创造者:Daniel Sleator 和 Robert Ta ...
- 纸上谈兵:伸展树(splay tree)
作者:Vamei 出处:http://www.cnblogs.com/vamei 欢迎转载,也请保留这段声明.谢谢! 我们讨论过,树的搜索效率与树的深度有关.二叉搜索树的深度可能为n,这种情况下,每次 ...
- SplayTree伸展树的非递归实现(自底向上)
Splay Tree 是二叉查找树的一种,它与平衡二叉树.红黑树不同的是,Splay Tree从不强制地保持自身的平衡,每当查找到某个节点n的时候,在返回节点n的同时,Splay Tree会将节点n旋 ...
- 伸展树(一)之 图文解析 和 C语言的实现
概要 本章介绍伸展树.它和"二叉查找树"和"AVL树"一样,都是特殊的二叉树.在了解了"二叉查找树"和"AVL树"之后, ...
- 伸展树(二)之 C++的实现
概要 上一章介绍了伸展树的基本概念,并通过C语言实现了伸展树.本章是伸展树的C++实现,后续再给出Java版本.还是那句老话,它们的原理都一样,择其一了解即可. 目录1. 伸展树的介绍2. 伸展树的C ...
- 伸展树(三)之 Java的实现
概要 前面分别通过C和C++实现了伸展树,本章给出伸展树的Java版本.基本算法和原理都与前两章一样.1. 伸展树的介绍2. 伸展树的Java实现(完整源码)3. 伸展树的Java测试程序 转载请注明 ...
- hdu1890 伸展树(区间反转)
对于大神来说这题是水题.我搞这题花了快2天. 伸展树的优点有什么,就是树不管你怎么旋转序列是不会改变得,并且你要使区间反转,只要把第k大的点转到根结点,那么它的左子树就是要交换的区间[l,r),然后交 ...
- POJ 3580 (伸展树)
题目链接: http://poj.org/problem?id=3580 题目大意:对一个序列进行以下六种操作.输出MIN操作的结果. 解题思路: 六个操作,完美诠释了伸展树有多么吊.注意,默认使用L ...
- Splay 伸展树
废话不说,有篇论文可供参考:杨思雨:<伸展树的基本操作与应用> Splay的好处可以快速分裂和合并. ===============================14.07.26更新== ...
- UVa 11922 - Permutation Transformer 伸展树
第一棵伸展树,各种调试模板……TVT 对于 1 n 这种查询我处理的不太好,之前序列前后没有添加冗余节点,一直Runtime Error. 后来加上冗余节点之后又出了别的状况,因为多了 0 和 n+1 ...
随机推荐
- 充分发挥 JavaScript 语言的优势
尽管我在生产环境中使用 JavaScript 长达 8 年之久了,但是,直到最近 2 年,我才开始学习如何正确地编写 JavaScript 代码,根据我对人们的理解,很多开发者都有类似经历.我们有相当 ...
- eclipse3.7 安装maven插件与scm
转自:http://blacksonny.iteye.com/blog/1900275 最近要使用maven进行开发,之前的eclipse3.7 使用一下两个地址安装好了插件,如下: maven插件 ...
- PHP数据结构:栈、队列、堆、固定数组
数据结构:栈 队列: 堆: 固定尺寸的数组:
- Java 常调用的Webservice接口的方法
WebService是基于Web的服务,WebService使用SOAP协议实现跨编程语言和跨操作系统平台,接收和响应外部系统的某种请求,从而实现远程调用.WebService采用HTTP协议传输数据 ...
- HTML--鼠标事件
<!DOCTYPE html> <html> <head> <meta http-equiv="Content-Type" content ...
- python进阶之路4.2---装饰器
*:first-child { margin-top: 0 !important; } body>*:last-child { margin-bottom: 0 !important; } /* ...
- tomcat线程数查看
获取tomcat进程pid ps -ef|grep tomcat 统计该tomcat进程内的线程个数 ps -Lf 29295 |wc -l
- C# 将窗口移动到指定位置
private void button1_Click(object sender, EventArgs e) { Frm f = new Frm(); f.StartPosition = FormSt ...
- sealed 修饰符
当对一个类应用 sealed 修饰符时,此修饰符会阻止其他类从该类继承. 在下面的示例中,类 B 从类 A 继承,但是任何类都不能从类 B 继承. class A {} sealed class B ...
- VS2010 ReportViewer导出文件下载保存不能识别文件类型
今天测试项目时,突然发现导出报表下载保存的保存,不能识别文件的类型,文件名称为:.xls[3] 检查代码发现在指定报表路径时多了一个方法: ReportViewer1.LocalReport.Load ...