• P3165 [CQOI2014]排序机械臂 (splay)


    题意

    (n)个物品,依次排列,每个物品都有一个高度(hi)
    (n)次操作,第(i)次操作将区间 [位置(i),第(i)低的物品(多个时取靠左的优先)的位置]翻转
    回答一个序列,第(i)个数表示每次操作前第(i)低的物品所在位置

    思路

    利用(splay)进行多次区间翻转的一道题。
    建立(n)个节点,节点(i)表示位置(i),一开始我们将splay类似线段树一样建好,其结点中序遍历就是(1,2,...,n−1,n)
    我们将原本的物品高度升序排列,高度相同按位置升序排列。
    然后每次就是找到第(i)高度的物品的结点(k),此时(splay)的结点(k)(splay)中序遍历所在的位置(从左到右数第几个),就是经过(i−1)次翻这个位置所对应的是最初始序列的第(k)个位置。
    将结点(k)移动到根,然后查询左儿子子树大小就是答案了。
    翻转原序列就是(splay)的一个基本操作了。
    注意:每次要先把元素旋转到根得到他的排名在反转区间,所以在这里(splay)里面也要加(push)下推。

    #include<bits/stdc++.h>
    using namespace std;
    const int maxx = 1e5+10;
    const int inf = 0x3f3f3f3f;
    struct node
    {
        int p,id;
        bool operator < (const node &t)const
        {
            if(p==t.p)return id<t.id;
            return p<t.p;
        }
    }a[maxx];
    int ch[maxx][2],fa[maxx],siz[maxx],lazy[maxx];
    int rt;
    int get(int x)
    {
        return ch[fa[x]][1]==x;
    }
    void update(int x)
    {
        if(x)siz[x]=siz[ch[x][0]]+siz[ch[x][1]]+1;
    }
    void pushdown(int x)
    {
        if(x&&lazy[x])
        {
            lazy[ch[x][0]]^=1;
            lazy[ch[x][1]]^=1;
            swap(ch[x][0],ch[x][1]);
            lazy[x]=0;
        }
    }
    void rotate(int x)
    {
        int y=fa[x],z=fa[y],k=get(x);
        pushdown(x);pushdown(y);
        ch[y][k]=ch[x][k^1];fa[ch[y][k]]=y;
        ch[x][k^1]=y;fa[y]=x;fa[x]=z;
        if(z)ch[z][ch[z][1]==y]=x;
        update(y);update(x);
    }
    void splay(int x,int goal)
    {
        for(int y;(y=fa[x])!=goal;rotate(x))
        {
            pushdown(fa[y]),pushdown(y),pushdown(x);
            if(fa[y]!=goal)rotate((get(x)==get(y))?y:x);
        }
        if(goal==0)rt=x;
    }
    int findkth(int k)
    {
        int x=rt;
        while(1)
        {
            pushdown(x);
            if(k<=siz[ch[x][0]])x=ch[x][0];
            else
            {
                k-=siz[ch[x][0]]+1;
                if(!k)return x;
                x=ch[x][1];
            }
        }
    }
    int build(int l,int r,int f)
    {
        if(l>r)return 0;
        int mid=(l+r)/2;
        fa[mid]=f;
        ch[mid][0]=build(l,mid-1,mid);
        ch[mid][1]=build(mid+1,r,mid);
        update(mid);
        return mid;
    }
    void reverse(int x,int y)
    {
        int l=x-1,r=y+1;
        l=findkth(l);r=findkth(r);
        splay(l,0);splay(r,l);
        lazy[ch[ch[rt][1]][0]]^=1;
    }
    int main()
    {
        int n;
        scanf("%d",&n);
        for(int i=2;i<=n+1;i++)
            scanf("%d",&a[i].p),a[i].id=i;
        a[1].id=1,a[1].p=-inf;
        a[n+2].id=n+2,a[n+2].p=inf;
        sort(a+1,a+1+n+2);
        rt=build(1,n+2,0);
        for(int i=2;i<=n+1;i++)
        {
            splay(a[i].id,0);
            int ans=siz[ch[rt][0]]+1;
            printf("%d ",ans-1);
            reverse(i,ans);
        }
    }
    
  • 相关阅读:
    Mybatis 延迟加载策略
    Mybatis中的多表查询 多对多
    Mybatis中的多表查询 多对一,一对多
    Mybatis 的动态 SQL 语句
    Mybatis中的连接池
    判断一个对象是否为数组
    包装对象概念 (做好事不留名的雷锋)
    javascript 继承之拷贝,原型,类式
    ajax参数
    面向对象小实例之 选项卡
  • 原文地址:https://www.cnblogs.com/HooYing/p/12493634.html
Copyright © 2020-2023  润新知