• [CQOI2014]排序机械臂


    洛谷P3165 [CQOI2014]排序机械臂

    https://www.luogu.org/problem/show?pid=3165

    题目描述

    为了把工厂中高低不等的物品按从低到高排好序,工程师发明了一种排序机械臂。它遵循一个简单的排序规则,第一次操作找到摄低的物品的位置P1,并把左起第一个至P1间的物品反序;第二次找到第二低的物品的位置P2,并把左起第二个至P2间的物品反序...最终所有的物品都会被排好序。

    上图给出_个示例,第_次操作前,菝低的物品在位置4,于是把第1至4的物品反序;第二次操作前,第二低的物品在位罝6,于是把第2至6的物品反序...

    你的任务便是编写一个程序,确定一个操作序列,即每次操作前第i低的物品所在位置Pi,以便机械臂工作。需要注意的是,如果有高度相同的物品,必须保证排序后它们的相对位置关系与初始时相同。

    输入输出格式

    输入格式:

    第一行包含正整数n,表示需要排序的物品数星。

    第二行包含n个空格分隔的整数ai,表示每个物品的高度。

    输出格式:

    输出一行包含n个空格分隔的整数Pi。

    输入输出样例

    输入样例#1:
    6
    3 4 5 1 6 2
    输出样例#1:
    4 6 4 5 6 6
    基本框架:splay 区间反转+查询
    流程:
    1、数据排序
    排序规则:高度小的在前,若高度相同,位置靠前的在前
    2、建立平衡树,平衡树中直接存储物品的编号,即加上两个虚拟节点后,平衡树中的节点x,对应初始序列位置为x的点;平衡树的中序遍历,对应本次排序后的物品顺序
    物品的高度只在排序中有用,自建树开始高度完全没有用了
    3、对于输出物品位置p,将物品旋转至根节点,输出左子树大小+1即可
    4、区间反转
    注意维护反转标记
    #include<cstdio>
    #include<algorithm>
    #define N 100005
    using namespace std;
    int n,fa[N],siz[N],ch[N][2],root,tag[N];
    struct node
    {
        int i,k;
    }a[N];
    inline bool cmp(node p,node q)
    {
        if(p.k<q.k) return 1;
        if(p.k==q.k) return p.i<q.i;
        return 0;
    }
    inline void update(int k)
    {
        siz[k]=siz[ch[k][0]]+siz[ch[k][1]]+1;
    } 
    inline void build(int l,int r,int f)
    {
        if(l>r) return;
        int mid=l+r>>1;
        if(mid<f) ch[f][0]=mid;
        else ch[f][1]=mid;
        siz[mid]=1;fa[mid]=f;
        if(l==r) return;
        build(l,mid-1,mid);
        build(mid+1,r,mid);
        update(mid);
    }
    inline void down(int k)
    {
        tag[k]^=1;
        if(ch[k][0]) tag[ch[k][0]]^=1;
        if(ch[k][1]) tag[ch[k][1]]^=1;
        swap(ch[k][0],ch[k][1]);
    }
    inline void rotate(int x,int & goal)
    {
        int y=fa[x],z=fa[y],kind=ch[y][1]==x;
        if(y==goal) goal=x;
        else ch[z][ch[z][1]==y]=x;
        ch[y][kind]=ch[x][kind^1];ch[x][kind^1]=y;
        fa[y]=x;fa[x]=z;fa[ch[y][kind]]=y;
        update(y);
    }
    inline void splay(int x,int & goal)
    {
        while(x!=goal)
        {
            int y=fa[x],z=fa[y];
            if(tag[z]) down(z);
                if(tag[y]) down(y);
                    if(tag[x]) down(x);
            if(y!=goal)
            {
                if(ch[y][1]==x^ch[z][1]==y) rotate(x,goal);
                else rotate(y,goal);
            }
            rotate(x,goal);    
            update(x);
        }
    } 
    inline int find(int now,int k)
    {
        if(tag[now]) down(now);
        int l=ch[now][0],r=ch[now][1];
        if(siz[l]+1==k) return now;
        if(k<=siz[l])  return find(l,k);
        return find(r,k-siz[l]-1);
    }
    inline void reverse(int l,int r)
    {
        int x=find(root,l-1),y=find(root,r+1);
        splay(x,root);splay(y,ch[x][1]);
        tag[ch[y][0]]^=1;
    }
    int main()
    {
        scanf("%d",&n);
        for(int i=1;i<=n;i++) {scanf("%d",&a[i+1].k); a[i+1].i=i+1;}
        a[1].i=1;a[n+2].i=n+2;a[n+2].k=2000000001;
        sort(a+1,a+n+3,cmp);
        build(1,n+2,0);root=n+3>>1;
        int p;
        for(int i=2;i<=n;i++)
        {
            splay(a[i].i,root);
            p=siz[ch[root][0]]+1;
            printf("%d ",p-1);
            reverse(i,p);
        }
        printf("%d",n);
    }

    3个错误:

    ①、标记下传

    a.错误代码:

    inline void down(int k)
    {
    tag[k]^=1;
    tag[ch[k][0]]^=1;tag[ch[k][1]]^=1;
    swap(ch[k][0],ch[k][1]);
    }

    错因:没有判断是否有左右孩子,如果没有孩子,为0,标记下穿至0号节点

    而在splay里 下传x,y,z的标记,z可能没有,就是0,导致将0的标记错误的传给根节点

    这里也可以不用判断是否有左右孩子

    splay里下传z的标记时判断z是否存在即可

    b.splay中没有标记下传

    if(tag[z]) down(z);
    if(tag[y]) down(y);
    if(tag[x]) down(x);

    以前写的那个splay模板因为splay在find之后,而find标记下传了,所以splay不需要下传

    ②、排序

    错误代码:

    inline bool cmp(node p,node q)
    {
    return p.k<=q.k;
    }

    不能完成k相同时位置靠前的在前

    ③、查找位置

    开始写了一个splay模板中的查找代码

    错误代码:

    inline int findpos(int now,int x)
    {
    if(x==now) return 1;
    if(tag[now]) down(now);
    if(x<now) return findpos(ch[now][0],x);
    return siz[ch[now][0]]+1+findpos(ch[now][1],x);
    }

    错因:虽然一开始建立平衡树是按编号的大小顺序建立的,但建立后,区间的反转时平衡树的节点间没有大小关系,所以不能根据now和x的大小查找x

    其实只要将x旋转至根节点,输出左子树大小+1即可

    思维太死板、模式化

     

  • 相关阅读:
    自动化测试过程中所入的坑3——解决问题思维的转换
    自动化测试所入的坑2
    js原生触发angular事件
    Selenium2Library源码中browser的传递
    Selenium自动化测试中的等待
    Android adb 命令学习笔记
    Robot学习笔记
    Xpath 与Css 定位方式的比较
    Selenium填坑笔记
    python批量更改文件名
  • 原文地址:https://www.cnblogs.com/TheRoadToTheGold/p/6416668.html
Copyright © 2020-2023  润新知