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

BZOJ 1552 浅谈SPLAY维护区间最值

2017-08-27 20:34 288 查看


世界真的很大

虽然这道题算是splay的比较偏模板题了,但是自己想的话还是有难度

关键是怎么把SPLAY维护东西的思路转换过来,是关键

写起来虽然的却有点多但是却是意外的好调

看题先:

description:



input

输入共两行,第一行为一个整数N,N表示物品的个数,1<=N<=100000。第二行为N个用空格隔开的正整数,表示N个物品最初排列的编号。


output

输出共一行,N个用空格隔开的正整数P1,P2,P3…Pn,(1 < = Pi < = N),Pi表示第i次操作前第i小的物品所在的位置。 注意:如果第i次操作前,第i小的物品己经在正确的位置Pi上,我们将区间[Pi,Pi]反转(单个物品)。


区间翻转比较好说,关键是怎么在维护序列时同时维护最小值

考虑普通平衡树在维护值域时维护最小值,就是平衡树的最左边

但是这道题维护的并不是值域,而是序列

考虑平衡树维护值域时,不仅可以知道最小值,还可以知道所有的值域信息,而这道题里面只需要知道最小值,维护值域不免有些浪费

考虑在维护序列时平衡树的每一个节点及其子树对应的是序列上连续的一段区间,这不免和线段树有些相似

而线段树维护最小值就只需要维护最小值就行了,所以我们平衡树也需要这么干

但不同的是线段树的结构是不变的,而平衡树的结构是不断改变的,并且为了对应到区间里面去,我们需要维护的,不再是最小值而已,而是包含最小值的节点的指针

注意update的时候多加一个维护最小值指针的东西

SPLAY的时候需要pushdown,原来一直不知道。。。

完整代码:

#include<stdio.h>
#include<stack>
#include<algorithm>
using namespace std;

const int INF=0x3f3f3f3f;

struct number
{
int val,id;
}aa[200010];

struct node
{
int sum,flag,siz;
node *ch[2],*fa,*mst;
void pushdown(node *nd)
{
if(flag)
{
swap(ch[0],ch[1]);
if(ch[0]!=nd) ch[0]->flag^=1;
if(ch[1]!=nd) ch[1]->flag^=1;
flag=0;
}
}
void update()
{
if(ch[0]->mst->sum < ch[1]->mst->sum) mst=ch[0]->mst;
else mst=ch[1]->mst;
if(sum<mst->sum) mst=this ;
siz=ch[0]->siz+ch[1]->siz+1;
}
}pool[1000010],*tail=pool,*root,*null;

stack <node*> stk;

int n,m,a[200010],ans[200010];

bool cmp(const number &a,const number &b)
{
if(a.val==b.val) return a.id<b.id;
else return a.val<b.val;
}

void init()
{
null=++tail;
null->siz=0;
null->ch[0]=null->ch[1]=null->mst=null;
null->flag=0;
null->sum=INF;
}

node* newnode(node *fa)
{
node *nd=++tail;
nd->fa=fa;
nd->siz=1;
nd->ch[1]=nd->ch[0]=nd->mst=null;
nd->flag=0;
return nd;
}

void rot ( node*& x, int d )
{
node* y=x->fa;
y->ch[!d]=x->ch[d];
if(x->ch[d]!= null) x->ch[d]->fa=y ;
x->fa=y->fa ;
if(y->fa!=null)
(y==y->fa->ch[0]) ? y->fa->ch[0]=x : y->fa->ch[1]=x;
x->ch[d]=y;
y->fa =x;
x->update();
y->update();
}

node *build(node *fa,int lf,int rg)
{
if(lf>rg) return null;
node *nd=newnode(fa);
if(lf==rg)
{
nd->sum=a[lf];
nd->mst=nd;
return nd;
}
int mid=(lf+rg)>>1;
nd->sum=a[mid];
nd->mst=nd;
nd->ch[0]=build(nd,lf,mid-1);
nd->ch[1]=build(nd,mid+1,rg);
nd->update();
return nd;
}

void Splay(node *nd,node *tar)
{
for(node *i=nd;i!=tar;i=i->fa)
stk.push(i);
while(!stk.empty()) stk.top()->pushdown(null) ,stk.pop();
while(nd->fa!=tar)
{
node *ne=nd->fa;
if(nd==ne->ch[0])
{
if(ne->fa!=tar&&ne==ne->fa->ch[0])
rot(ne,1);
rot(nd,1);
}
else
{
if(ne->fa!=tar&&ne==ne->fa->ch[1])
rot(ne,0);
rot(nd,0);
}
}
if(tar==null) root=nd;
}

node *kth(node *nd,int K)
{
nd->pushdown(null);
if(nd->ch[0]->siz+1==K) return nd;
if(nd->ch[0]->siz+1>K) return kth(nd->ch[0],K);
else return kth(nd->ch[1],K-nd->ch[0]->siz-1);
}

void rev(int L,int R)
{
node *x=kth(root,L);node *y=kth(root,R+2);
Splay(x,null);
Splay(y,root);
y->ch[0]->flag^=1;
}

node *qumin(int pos)
{
node *x=kth(root,pos),*y=kth(root,n+2);
Splay(x,null);
Splay(y,root);
return y->ch[0]->mst;
}

int main()
{
init();
scanf("%d",&n);
for(int i=1;i<=n;i++)
scanf("%d",&aa[i].val),aa[i].id=i;
sort(aa+1,aa+n+1,cmp);
for(int i=1;i<=n;i++)
a[aa[i].id]=i;
a[0]=a[n+1]=INF;
root=build(null,0,n+1);
for(int i=1;i<=n;i++)
{
node *x=qumin(i);
Splay(x,null);
ans[i]=x->ch[0]->siz;
rev(i,ans[i]);
}
for(int i=1;i<n;i++)
printf("%d ",ans[i]);
printf("%d",ans
);
return 0;
}
/*
EL PSY CONGROO
*/


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