【平衡树维护序列】BZOJ3506(Cqoi2014)[排序机械臂]题解

题目概述

BZOJ原题意:同OJ1552。BZOJ1552:权限题。城市套路深,我要回农村。

给出一个长度为 n 的序列,执行 n 次操作,第 i 次操作需要找到 [i,n] 中最小的数所在的位置 p ,并翻转 [i,p]

ps:如果相同取位置靠前的。

解题报告

QAQ,查了两天,发现我没看到相同取靠前。于是我用基数排序将相同的硬是搞成了不相同的……

直接Splay,只不过要多实现一个得到排名的函数,需要记录 fa

示例程序

#include<cstdio>
#include<algorithm>
#define fr first
#define sc second
#define mp make_pair
using namespace std;
const int maxn=100000;

int n,a[maxn+5],b[maxn+5],ha[maxn+5];
struct node
{
    node *son[2],*fa;int si,ID;pair<int,node*> MIN;bool flip;
    node(node *p=0,node *f=0,int k=0,int s=1) {son[0]=son[1]=p;fa=f;ID=k;si=s;MIN=mp(ID,this);flip=false;}
    inline int cmp(int &k) {if (k<=son[0]->si) return 0;if (k>son[0]->si+1) return k-=son[0]->si+1,1;return -1;}
    inline void Pushup() {si=son[0]->si+1+son[1]->si;MIN=min(son[0]->MIN,son[1]->MIN);MIN=min(MIN,mp(ID,this));}
    inline void Addflip() {swap(son[0],son[1]);flip^=1;}
    inline void Pushdown() {if (!flip) return;flip=false;son[0]->Addflip();son[1]->Addflip();}
}nil(&nil,&nil,maxn+5,0);
typedef node* P_node;
node tem[maxn+5];P_node si=tem,null=&nil,ro;

#define newnode(fa,k) (*si=node(null,fa,k),si++)
P_node Build(int L,int R,P_node fa=null)
{
    if (L>R) return null;int mid=L+(R-L>>1);P_node now=newnode(fa,a[mid]);
    return now->son[0]=Build(L,mid-1,now),now->son[1]=Build(mid+1,R,now),now->Pushup(),now;
}
inline void Rotate(P_node &p,int d)
{
    P_node t=p->son[d^1];p->son[d^1]=t->son[d];t->son[d]=p;
    t->fa=p->fa;p->fa=t;if (p->son[d^1]!=null) p->son[d^1]->fa=p;
    p->Pushup();t->Pushup();p=t;
}
void Splay(P_node &p,int k)
{
    p->Pushdown();int d=p->cmp(k);
    if (~d)
    {
        P_node &P=p->son[d];P->Pushdown();int D=P->cmp(k);
        if (~D) {Splay(P->son[D],k);if (d==D) Rotate(p,d^1); else Rotate(P,D^1);}
        Rotate(p,d^1);
    }
}
inline void getLR(int L,int R) {R+=2;Splay(ro,L);ro->cmp(R);Splay(ro->son[1],R);}
#define NOW ro->son[1]->son[0]
inline void Flip(int L,int R) {getLR(L,R);NOW->Addflip();}
#define Son(p) ((p)==(p)->fa->son[1])
inline int getrk(P_node p,P_node ro) //得到排名
{
    static int top=0,rk;static P_node stk[maxn+5];
    for (P_node i=p;i!=ro;i=i->fa) stk[++top]=i;stk[++top]=ro;
    while (top) stk[top--]->Pushdown();rk=p->son[0]->si+1;
    for (;p!=ro;p=p->fa) if (Son(p)) rk+=p->fa->son[0]->si+1;return rk;
}
inline int Find(int x)
{
    int L=1,R=b[0];
    for (int mid=L+(R-L>>1);L<=R;mid=L+(R-L>>1))
        if (b[mid]<=x) L=mid+1; else R=mid-1;
    return R;
}
int main()
{
    freopen("program.in","r",stdin);
    freopen("program.out","w",stdout);
    scanf("%d",&n);for (int i=1;i<=n;i++) scanf("%d",&a[i]),b[i]=a[i];
    sort(b+1,b+1+n);b[0]=unique(b+1,b+1+n)-(b+1);for (int i=1;i<=n;i++) ha[a[i]=Find(a[i])]++;
    for (int i=1;i<=b[0];i++) ha[i]+=ha[i-1];for (int i=n;i>=1;i--) a[i]=ha[a[i]]--;ro=Build(0,n+1);
    for (int i=1;i<=n;i++)
    {
        getLR(i,n);int rk=getrk(NOW->MIN.sc,NOW)+i-1;printf("%d",rk);
        Flip(i,rk);putchar(i<n?' ':'\n');
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值