您的位置:首页 > 运维架构

hdu4453-Looploop(伸展树)

2016-07-08 10:20 344 查看
题目有很多图,不好粘贴。。。。。

题意:给出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+7;
const int maxn=200005;
int A[maxn],cnt;  //A数组保存数,cnt是节点标号,我是用数组模拟的
struct treap
{
treap* son[2];  //左右儿子
int v,s,add,lazy;  //v是值,s是大小,add是懒惰标记增加的值,lazy是懒惰标记是否需要翻转
treap(){ v=s=add=lazy=0; son[0]=son[1]=NULL; }
treap(int nv);
int rk(){ return son[0]->s+1; }  //排名,第几个数
int cmp(int k)  //比较,如果相等返回-1,小于返回0,大于1
{
if(k==rk()) return -1;
return k<rk()?0:1;
}
void pushup(){ s=son[0]->s+son[1]->s+1; }  //更新大小
void pushdown()  //处理懒惰标记
{
if(lazy)
{
swap(son[0],son[1]);
son[0]->lazy^=1;
son[1]->lazy^=1;
lazy=0;
}
if(add)
{
v+=add;
son[0]->add+=add;
son[1]->add+=add;
add=0;
}
}
}null,tr[maxn];
treap::treap(int nv)
{
v=nv;
s=1;
add=lazy=0;
son[0]=son[1]=&null;
}
treap* NewNode(int x)
{
tr[cnt]=treap(x);
return tr+cnt++;
}
struct splaytree
{
int Size;
treap* root;
splaytree(){ Size=0; root=&null; }
void Rotate(treap* &t,int d)  //翻转操作
{
t->pushdown();
treap* p=t->son[d^1];
p->pushdown();
t->son[d^1]=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!=-1)
{
if(d) Splay(t->son[d],k- t->rk());
else Splay(t->son[d],k);
Rotate(t,d^1);
}
}
void Build(treap* &t,int le,int ri)  //将N个数建成一棵树
{
if(le>ri) return;
int mid=(le+ri)/2;
t=NewNode(A[mid]);
Build(t->son[0],le,mid-1);
Build(t->son[1],mid+1,ri);
t->pushup();
}
void Add(treap* &t,int k,int a)  //加值
{
Splay(t,k);
t->v+=a;
t->son[0]->add+=a;
}
void Reverse(treap* &t,int k)  //翻转
{
Splay(t,k);
treap* p=t->son[1];
t->son[1]=&null;
t->pushup();
t->lazy=1;
t->pushdown();
Splay(t,k);
t->son[1]=p;
t->pushup();
}
void Insert(treap* &t,int x)  //插入
{
Splay(t,1);
treap* p=NewNode(x);
p->son[1]=t->son[1];
p->pushup();
t->son[1]=p;
t->pushup();
Size++;
}
void Remove(treap* &t)  删除
{
Splay(t,1);
treap* next=t->son[1];
t=next;
t->pushdown();
Size--;
}
void Move(treap* &t,int x)  //移动
{
if(x==1)
{
Splay(t,Size);
treap* p=t->son[0];
t->son[0]=&null;
p->pushdown();
Splay(p,1);
t->son[1]=p;
t->pushup();
}
else
{
Splay(t,1);
treap* p=t->son[1];
t->son[1]=&null;
p->pushdown();
Splay(p,Size-1);
t->son[0]=p;
t->pushup();
}
}
};
int N,M,K1,K2;
int main()
{
int Case=0;
while(scanf("%d%d%d%d",&N,&M,&K1,&K2)!=EOF)
{
if(!N&&!M&&!K1&&!K2) break;
for(int i=1;i<=N;i++) scanf("%d",&A[i]);
cnt=0;
splaytree spt;
spt.Build(spt.root,1,N);
spt.Size=N;
printf("Case #%d:\n",++Case);
while(M--)
{
char op[10];
int x;
scanf("%s",op);
if(strcmp(op,"add")==0)
{
scanf("%d",&x);
spt.Add(spt.root,K2,x);
}
else if(strcmp(op,"reverse")==0) spt.Reverse(spt.root,K1);
else if(strcmp(op,"insert")==0)
{
scanf("%d",&x);
spt.Insert(spt.root,x);
}
else if(strcmp(op,"delete")==0) spt.Remove(spt.root);
else if(strcmp(op,"move")==0)
{
scanf("%d",&x);
spt.Move(spt.root,x);
}
else
{
spt.Splay(spt.root,1);
printf("%d\n",spt.root->v);
}
}
}
return 0;
}


View Code
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: