【JZOJ3599】【CQOI2014】排序机械臂(splay or 非旋treap区间翻转)

Problem

这里写图片描述

Hint

对于30%的数据 1<=n<1000

对于100%的数据 1<=n<=100000 ,1<=ai<=2,000,000,000

Solution

splay

  先讲一讲splay吧。
  考虑以物品的序号为下标建一棵splay,维护物品的中序遍历。
  首先排个序,确定每次找到的是哪个数。
  设这次找到第i个数,我们可以对点i进行splay操作,然后1~i-1在i的左儿子,i+1~n在i的右儿子;直接把翻转标记打在左儿子上;然后,删掉点i,消除它对后面的影响。
  时间复杂度: O ( n l o g 2 n )

Code

  囿于实在太水了,故没打。

非旋treap

  考虑按照splay做法的思路做。
  但槽点就在于,我们不能用treap进行splay操作。
  于是,我们可以考虑对于每次找到的数i,我们都求出它当前的排名k;将[1..k-1]分离出来,打上翻转标记,然后和[k+1..n]合并。
  但是,我们不能直接记录一个满足二叉排序树性质的键值,因为它有翻转操作,性质可能会被打破。譬如点1的值为1,点2的值为2,点3的值为3,点1为点2的左儿子,点3为点2的右儿子;则我们翻转点2的子树时,将会令点1变成点2的右儿子,点3变成点2的左儿子。这就不符合二叉排序树的性质。
  所以,我们在求点x的排名时,可以先将根到x的标记清除,然后赋排名的初值ans=t[t[x].l].sz+1;(x的排名大于等于它左子树中每个点的排名以及它自身的排名)。从x一路跳上去,如果我们在某次跳时发现x是右儿子,则它的排名又大于f(设f为它的父亲)以及f的左子树,故令ans+=t[t[f].l].sz+1;这样,就能在 O ( ) 的时间内很好地求出某个点的排名;而我们又知道,treap的树高是期望 l o g 2 n 的,所以可以为所欲为。
  时间复杂度: O ( n l o g 2 n )

Code

#include <cstdio>
#include <algorithm>
#include <ctime>
#define fi first
#define se second
#define mp make_pair
#define fo(i,a,b) for(i=a;i<=b;i++)
using namespace std;
typedef pair<int,int> P;

const int N=1e5+1,inf=0x7FFFFFFF;
int i,n,root,cnt;
struct Treap
{
    int pri,l,r,f,sz;bool tag;
    inline void newnode()
    {
        pri=rand();
        l=r=0;
        sz=1;
    }
}t[N];
inline void evert(int v)
{
    t[v].tag^=1;
    swap(t[v].l,t[v].r);
}
inline void push(int v)
{
    if(!t[v].tag)return;
    evert(t[v].l);
    evert(t[v].r);
    t[v].tag=0;
}
inline void update(int v){t[v].sz=1+(t[v].l?t[t[v].l].sz:0)+(t[v].r?t[t[v].r].sz:0);}
inline void link(int f,int x,bool k)
{
    k ? t[f].r=x : t[f].l=x;
    t[x].f=f;
}
int merge(int a,int b)
{
    push(a); push(b);
    return !a||!b?a+b : 
    (t[a].pri<t[b].pri?
    (link(a,merge(t[a].r,b),1),update(a),a):
    (link(b,merge(a,t[b].l),0),update(b),b));
}
P split(int o,int k)
{
    if(!o)return mp(0,0);
    push(o);
    if(!k)return mp(0,o);
    P y;
    return t[t[o].l].sz>=k?
    (y=split(t[o].l,k               ),link(o,y.se,0),update(o),y.se=o,y):
    (y=split(t[o].r,k-t[t[o].l].sz-1),link(o,y.fi,1),update(o),y.fi=o,y);
}
int d[N];
void clear(int x)
{
    d[0]=0;
    for(;x;x=t[x].f) d[++d[0]]=x;
    while(d[0]) push(d[d[0]--]);
}
int rank(int x)
{
    clear(x);
    int ans=t[t[x].l].sz+1,f;
    for(;x;x=f)
    {
        f=t[x].f;
        if(t[f].r==x) ans+=t[t[f].l].sz+1;
    }
    return ans;
}
inline void insert(int v)
{
    root=merge(root,v);
}
//treap

struct object
{
    int h,i;
    inline bool operator<(const object y)const{return h<y.h||h==y.h&&i<y.i;}
}a[N];

void scan()
{
    scanf("%d",&n);
    fo(i,1,n)
    {
        scanf("%d",&a[i].h);
        a[i].i=i;
        t[++cnt].newnode();
        insert(cnt);
    }
}

void work()
{
    sort(a+1,a+n+1);

    fo(i,1,n)
    {
        int k=rank(a[i].i);
        printf("%d ",k+i-1);
        P x=split(root,k-1);
        evert(x.fi);
        P y=split(x.se,1);
        root=merge(x.fi,y.se);
    }
}

int main()
{
    scan();
    work();
}

猜你喜欢

转载自blog.csdn.net/qq_36551189/article/details/80752329