• [Luogu] 排序机械臂


    https://www.luogu.org/problemnew/solution/P3165

    预处理

    我们会发现一个问题:高度是无序的,而splay中要求有序,否则kth不能正确求解。
    不需要求高度,只要求位置。
    所以,用结构体存入 高度 与 下标,按高度排序,然后就可以把高度丢一边了(一波sao操作)。
    记得头尾添加两个节点。。。
    建树
    正常 nlogn 可能会被卡常,所以,类似于线段树的建树,分此节点与左右儿子节点。
    区间第k大
    正常kth
    区间翻转
    首先,需要把所求的节点(即排序前下标为id的节点) splay 到 root 。
    那么答案就是root左孩子的节点个数(因为有哨兵节点,所以+1-1抵消),记为s。
    然后,取出 [i+1 , s+1] 这段区间,即:
    将i节点 splay 到根,s+2节点 splay 到i的右节点。
    再将s+2的左孩子打上翻转标记即可。

    #include<iostream>
    #include<algorithm>
    #include<cstdio>
    #define MAXN 100010
    #define MAX 999999999//最值
    using namespace std;
    int n,size=1,root=0;
    struct node {
        int x,id;
    } b[MAXN];
    namespace splay {
        struct Splay {
            int f,s,flag,son[2];
            int v;
        } a[MAXN];
        inline void clean(int rt) { //清空节点
            a[rt].son[0]=a[rt].son[1]=a[rt].f=a[rt].s=a[rt].flag=a[rt].v=0;
        }
        inline void pushup(int rt) { //上传
            if(!rt)return;
            a[rt].s=a[a[rt].son[0]].s+a[a[rt].son[1]].s+1;
        }
        inline void pushdown(int rt) { //标记下传
            if(!rt||!a[rt].flag)return;//记得这句
            a[a[rt].son[0]].flag^=1;
            a[a[rt].son[1]].flag^=1;
            a[rt].flag^=1;
            swap(a[rt].son[0],a[rt].son[1]);
        }
        inline void turn(int rt,int k) { //旋转
            int x=a[rt].f,y=a[x].f;
            a[x].son[k^1]=a[rt].son[k];
            if(a[rt].son[k])a[a[rt].son[k]].f=x;
            a[rt].f=y;
            if(y)a[y].son[a[y].son[1]==x]=rt;
            a[x].f=rt;
            a[rt].son[k]=x;
            pushup(x);
            pushup(rt);
        }
        void splay(int rt,int ancestry) { //伸展
            while(a[rt].f!=ancestry) {
                int x=a[rt].f,y=a[x].f;
                pushdown(y);
                pushdown(x);
                pushdown(rt);//每次都要下传
                if(y==ancestry)turn(rt,a[x].son[0]==rt);
                else {
                    int k=a[y].son[0]==x?1:0;
                    if(a[x].son[k]==rt) {
                        turn(rt,k^1);
                        turn(rt,k);
                    } else {
                        turn(x,k);
                        turn(rt,k);
                    }
                }
            }
            if(ancestry==0)root=rt;
        }
        inline int newnode(int x) { //建立新节点
            int rt=size++;
            clean(rt);
            a[rt].v=x;
            a[rt].s=1;
            return rt;
        }
        int buildtree(int l,int r) { //建树
            if(l>r)return 0;
            int mid=l+r>>1,lson=0,rson=0;
            lson=buildtree(l,mid-1);
            int rt=newnode(b[mid].x);
            rson=buildtree(mid+1,r);
            a[rt].son[0]=lson;
            a[rt].son[1]=rson;
            if(lson)a[lson].f=rt;
            if(rson)a[rson].f=rt;
            pushup(rt);//一定要有这句!
            return rt;
        }
        int kth(int rt,int k) { //第k大值
            if(a[rt].s<k)return 0;
            while(1) {
                pushdown(rt);//下传
                int y=a[rt].son[0];
                if(k>a[y].s+1) {
                    k-=a[y].s+1;
                    rt=a[rt].son[1];
                } else if(k<=a[y].s)rt=y;
                else return rt;
            }
        }
        inline void reverge(int i) { //区间翻转
            splay(b[i].id+1,0);//记得加1(有哨兵节点)
            int s=a[a[root].son[0]].s;
            printf("%d ",s);
            int front=kth(root,i),next=kth(root,s+2);
            splay(front,0);
            splay(next,front);
            a[a[next].son[0]].flag^=1;//打上标记
        }
    }
    inline int read() {
        int date=0,w=1;
        char c=0;
        while(c<'0'||c>'9') {
            if(c=='-')w=-1;
            c=getchar();
        }
        while(c>='0'&&c<='9') {
            date=date*10+c-'0';
            c=getchar();
        }
        return date*w;
    }
    bool cmp(const node &x,const node &y) {
        if(x.x==y.x)return x.id<y.id;
        return x.x<y.x;
    }
    void init() { //预处理+读入+工作
        n=read();
        for(int i=1; i<=n; i++) {
            b[i].x=read();
            b[i].id=i;
        }
        b[0].x=-MAX;
        b[0].id=1;
        b[n+1].x=MAX;
        b[n+1].id=n+1;//两个哨兵节点
        sort(b+1,b+n+1,cmp);
        root=splay::buildtree(0,n+1);
        for(int i=1; i<=n-1; i++)splay::reverge(i);
        printf("%d
    ",n);//最后一个一定是 n
    }
    int main() {
        init();
        return 0;
    }
  • 相关阅读:
    Android官方数据绑定框架DataBinding*
    Application 使用分析*
    Android HandlerThread与IntentService*
    Android中SQLite应用详解*
    Android开发中,那些让您觉得相见恨晚的方法、类或接口*
    巧用ViewPager 打造不一样的广告轮播切换效果*
    Android-Universal-Image-Loader的缓存处理机制与使用 LruCache 缓存图片*
    Android Volley完全解析*
    Android 蓝牙*
    Android自定义View
  • 原文地址:https://www.cnblogs.com/shandongs1/p/9007019.html
Copyright © 2020-2023  润新知