题目有很多图,不好粘贴。。。。。

题意:给出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(伸展树)的更多相关文章

  1. Splay伸展树学习笔记

    Splay伸展树 有篇Splay入门必看文章 —— CSDN链接 经典引文 空间效率:O(n) 时间效率:O(log n)插入.查找.删除 创造者:Daniel Sleator 和 Robert Ta ...

  2. 纸上谈兵:伸展树(splay tree)

    作者:Vamei 出处:http://www.cnblogs.com/vamei 欢迎转载,也请保留这段声明.谢谢! 我们讨论过,树的搜索效率与树的深度有关.二叉搜索树的深度可能为n,这种情况下,每次 ...

  3. SplayTree伸展树的非递归实现(自底向上)

    Splay Tree 是二叉查找树的一种,它与平衡二叉树.红黑树不同的是,Splay Tree从不强制地保持自身的平衡,每当查找到某个节点n的时候,在返回节点n的同时,Splay Tree会将节点n旋 ...

  4. 伸展树(一)之 图文解析 和 C语言的实现

    概要 本章介绍伸展树.它和"二叉查找树"和"AVL树"一样,都是特殊的二叉树.在了解了"二叉查找树"和"AVL树"之后, ...

  5. 伸展树(二)之 C++的实现

    概要 上一章介绍了伸展树的基本概念,并通过C语言实现了伸展树.本章是伸展树的C++实现,后续再给出Java版本.还是那句老话,它们的原理都一样,择其一了解即可. 目录1. 伸展树的介绍2. 伸展树的C ...

  6. 伸展树(三)之 Java的实现

    概要 前面分别通过C和C++实现了伸展树,本章给出伸展树的Java版本.基本算法和原理都与前两章一样.1. 伸展树的介绍2. 伸展树的Java实现(完整源码)3. 伸展树的Java测试程序 转载请注明 ...

  7. hdu1890 伸展树(区间反转)

    对于大神来说这题是水题.我搞这题花了快2天. 伸展树的优点有什么,就是树不管你怎么旋转序列是不会改变得,并且你要使区间反转,只要把第k大的点转到根结点,那么它的左子树就是要交换的区间[l,r),然后交 ...

  8. POJ 3580 (伸展树)

    题目链接: http://poj.org/problem?id=3580 题目大意:对一个序列进行以下六种操作.输出MIN操作的结果. 解题思路: 六个操作,完美诠释了伸展树有多么吊.注意,默认使用L ...

  9. Splay 伸展树

    废话不说,有篇论文可供参考:杨思雨:<伸展树的基本操作与应用> Splay的好处可以快速分裂和合并. ===============================14.07.26更新== ...

  10. UVa 11922 - Permutation Transformer 伸展树

    第一棵伸展树,各种调试模板……TVT 对于 1 n 这种查询我处理的不太好,之前序列前后没有添加冗余节点,一直Runtime Error. 后来加上冗余节点之后又出了别的状况,因为多了 0 和 n+1 ...

随机推荐

  1. 好用的QT连接

    QT属性控件项目https://github.com/lexxmark/QtnProperty比特币交易软件https://github.com/JulyIGHOR/QtBitcoinTrader导航 ...

  2. testng 提供参数

    获取页面元素属性,并把属性作为参数传递个测试方法,两桶不同的写法 1. @DataProvider public Iterator<Object[]> dp() { mySleep(500 ...

  3. HBase面试问题

    一.HBase的特点是什么 1.HBase一个分布式的基于列式存储的数据库,基于hadoop的hdfs存储,zookeeper进行管理. 2.HBase适合存储半结构化或非结构化数据,对于数据结构字段 ...

  4. altium designer 原理图复制出错

    复制原理图的时候最后弹出这种错误 InvalidParameter at 2510219C. AdvSch.dll, Base Address: 24C80000. Exception Occurre ...

  5. hdu 1240 Asteroids! (三维bfs)

    Asteroids! Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total ...

  6. Android中Service类onStartCommand

    Android开发的过程中,每次调用startService(Intent)的时候,都会调用该Service对象的onStartCommand(Intent,int,int)方法,然后在onStart ...

  7. 使用Dataset

    string sqlStr="Select * from Tb_news"; SqlDataAdapter myDa=new SqlDataAdapter(SqlStr,myCon ...

  8. js改变div宽度

    document.getElementById('Content_Right_id').style.width = document.documentElement.clientWidth - 250 ...

  9. Android与JS混编(js调用java)

    项目中需要使用android与js的混编来开发app. 下面就介绍一下吧. 有时候我们需要用js调用native控件,要想实现这个功能,我们需要做的就只有三步: 1.允许webview执行js脚本 2 ...

  10. NSDictionary使用小结

    http://blog.csdn.net/ms2146/article/details/8656787