BZOJ 3506 CQOI 2014 排序机械臂 Splay

题目大意:给出一个序列,给出一种排序方式,模拟这种排序方式排序,并输出每次找到的节点的位置。

思路:它让你做什么你就做什么,无非就是个Reverse,很简单。注意一下排序的时候权值相等的情况就行了。

CODE:

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define MAX 100010
#define INF 0x3f3f3f3f
using namespace std;

struct SplayTree{
    SplayTree *son[2],*father;
    bool reverse;
    int size;

    SplayTree();
    bool Check() {
        return father->son[1] == this;
    }
    void Combine(SplayTree *a,bool dir) {
        a->father = this;
        son[dir] = a;
    }
    void Reverse() {
        reverse ^= 1;
        swap(son[0],son[1]);
    }
    void PushUp() {
        size = son[0]->size + son[1]->size + 1;
    }
    void PushDown() {
        if(reverse) {
            son[0]->Reverse();
            son[1]->Reverse();
            reverse = false;
        }
    }
}none,*nil = &none,*root;
SplayTree:: SplayTree() {
    son[0] = son[1] = nil;
    reverse = false;
    size = 1;
}

struct Complex{
    int val,pos;
    SplayTree *a;

    bool operator <(const Complex &a)const {
        if(val == a.val)    return pos < a.pos;
        return val < a.val;
    }
    void Read(int p) {
        scanf("%d",&val);
        pos = p;
    }
}src[MAX];

int cnt;

void Pretreatment()
{
    nil->size = 0;
    nil->son[0] = nil->son[1] = nil->father = nil;
}

SplayTree *BuildTree(int l,int r)
{
    if(l > r)    return nil;
    int mid = (l + r) >> 1;
    SplayTree *re = new SplayTree();
    src[mid].a = re;
    re->Combine(BuildTree(l,mid - 1),false);
    re->Combine(BuildTree(mid + 1,r),true);
    re->PushUp();
    return re;
}

inline void Rotate(SplayTree *a,bool dir)
{
    SplayTree *f = a->father;
    f->PushDown(); a->PushDown();
    f->son[!dir] = a->son[dir];
    f->son[!dir]->father = f;
    a->son[dir] = f;
    a->father = f->father;
    f->father->son[f->Check()] = a;
    f->father = a;
    f->PushUp();
    if(f == root)   root = a;
}

inline void Splay(SplayTree *a,SplayTree *aim)
{
    while(a->father != aim) {
        if(a->father->father == aim)
            Rotate(a,!a->Check());
        else if(!a->father->Check()) {
            if(!a->Check())
                Rotate(a->father,true),Rotate(a,true);
            else    Rotate(a,false),Rotate(a,true);
        }
        else {
            if(a->Check())
                Rotate(a->father,false),Rotate(a,false);
            else    Rotate(a,true),Rotate(a,false);
        }
    }
    a->PushUp();
}

SplayTree *Find(SplayTree *a,int k)
{
    a->PushDown();
    if(a->son[0]->size >= k)   return Find(a->son[0],k);
    k -= a->son[0]->size;
    if(k == 1)  return a;
    return Find(a->son[1],k - 1);
}

inline void SplaySeg(int x,int y)
{
    x++,y++;
    Splay(Find(root,x - 1),nil);
    Splay(Find(root,y + 1),root);
}

int main()
{
    cin >> cnt;
    Pretreatment();
    for(int i = 1; i <= cnt; ++i)
        src[i].Read(i);
    src[0].val = src[cnt + 1].val = INF;
    root = BuildTree(0,cnt + 1);
    root->father = nil;
    sort(src + 1,src + cnt + 1);
    for(int i = 1; i <= cnt; ++i) {
        Splay(src[i].a,nil);
        printf("%d%c",root->son[0]->size," \n"[i == cnt]);
        SplaySeg(i,root->son[0]->size);
        root->son[1]->son[0]->Reverse();
    }
    return 0;
}

时间: 2024-10-06 00:07:11

BZOJ 3506 CQOI 2014 排序机械臂 Splay的相关文章

【BZOJ-1552&amp;3506】robotic sort&amp;排序机械臂 Splay

1552: [Cerc2007]robotic sort Time Limit: 5 Sec  Memory Limit: 64 MBSubmit: 806  Solved: 329[Submit][Status][Discuss] Description Input 输入共两行,第一行为一个整数N,N表示物品的个数,1<=N<=100000.第二行为N个用空格隔开的正整数,表示N个物品最初排列的编号. Output 输出共一行,N个用空格隔开的正整数P1,P2,P3…Pn,Pi表示第i次操作

[BZOJ3506] [Cqoi2014] 排序机械臂 (splay)

Description 同OJ1552 Input Output Sample Input Sample Output HINT Source Solution Q:哎不是同一道题吗为什么分两篇博客来写? A:当然是来骗浏览量了233333333,这里还是会放代码的,当然你左转BZOJ1552的题解也行. 1 #include <bits/stdc++.h> 2 using namespace std; 3 struct spaly 4 { 5 int c[2], fa, siz, rev;

【BZOJ3506】排序机械臂(Splay)

[BZOJ3506]排序机械臂(Splay) 题面 神TMBZOJ没有题面,感谢SYC的题面 洛谷的题面也不错 题解 对于每次旋转的物体 显然可以预处理出来 现在只要模拟旋转操作就行了 至于在哪里放标记的问题 我只在第K大放会鬼.. 所以在Splay里面也放了一次(和LCT一样的) 然而我每次都把排到了正确位置的元素直接给删掉了... 所以跑的很慢很慢... #include<iostream> #include<cstdio> #include<cstdlib> #i

[CQOI2014]排序机械臂

洛谷P3165 [CQOI2014]排序机械臂 https://www.luogu.org/problem/show?pid=3165 题目描述 为了把工厂中高低不等的物品按从低到高排好序,工程师发明了一种排序机械臂.它遵循一个简单的排序规则,第一次操作找到摄低的物品的位置P1,并把左起第一个至P1间的物品反序:第二次找到第二低的物品的位置P2,并把左起第二个至P2间的物品反序...最终所有的物品都会被排好序. 上图给出_个示例,第_次操作前,菝低的物品在位置4,于是把第1至4的物品反序:第二次

洛谷P3165 [CQOI2014]排序机械臂

题目描述 为了把工厂中高低不等的物品按从低到高排好序,工程师发明了一种排序机械臂.它遵循一个简单的排序规则,第一次操作找到摄低的物品的位置P1,并把左起第一个至P1间的物品反序:第二次找到第二低的物品的位置P2,并把左起第二个至P2间的物品反序...最终所有的物品都会被排好序. 上图给出_个示例,第_次操作前,菝低的物品在位置4,于是把第1至4的物品反序:第二次操作前,第二低的物品在位罝6,于是把第2至6的物品反序... 你的任务便是编写一个程序,确定一个操作序列,即每次操作前第i低的物品所在位

P3165 [CQOI2014]排序机械臂

P3165 [CQOI2014]排序机械臂 题目描述 为了把工厂中高低不等的物品按从低到高排好序,工程师发明了一种排序机械臂.它遵循一个简单的排序规则,第一次操作找到摄低的物品的位置P1,并把左起第一个至P1间的物品反序:第二次找到第二低的物品的位置P2,并把左起第二个至P2间的物品反序...最终所有的物品都会被排好序. 上图给出_个示例,第_次操作前,菝低的物品在位置4,于是把第1至4的物品反序:第二次操作前,第二低的物品在位罝6,于是把第2至6的物品反序... 你的任务便是编写一个程序,确定

LibreOJ2241 - 「CQOI2014」排序机械臂

Portal Description 给出一个\(n(n\leq10^5)\)个数的序列\(\{a_n\}\),对该序列进行\(n\)次操作.若在第\(i\)次操作前第\(i\)小的数在\(p_i\)位置,则翻转区间\([i,p_i]\).易知\(n\)次操作后序列会变为升序.求出每一次的\(p_i\). Solution splay. 题里的\(a_i\)是会重复的...所以先离散化一波,相同的数按位置排名.然后根据初始位置建一棵splay,每次将\(i\)旋转到根求左子树大小即可,区间翻转用

【BZOJ】【1552】【Cerc2007】robotic sort / 【3506】【CQOI2014】排序机械臂

Splay 离散化+Splay维护序列…… 好吧主要说一下我做这道题遇到的几个错误点: 1.离散化 2.由于找到的这个数的位置一定是大于等于 i 的,所以其实在把它splay到根以后,i 结点只能splay到它的左儿子,而不是右儿子……而且相应的,代表这个区间的应该是c[c[root][0]][1]呃……就是root的左儿子的右儿子= =整个反了一下……好吧不要在意这些细节,我也不知道为什么我突然要反过来写[捂脸熊] 3.进行了修改操作以后一定要立即splay修改的结点!在这题中就是当找到最小结

[BZOJ 1552] 排序机械臂

Splay大法是坠吼滴! 1552: [Cerc2007]robotic sort Time Limit: 5 Sec  Memory Limit: 64 MBSubmit: 436  Solved: 186[Submit][Status][Discuss] Description Input 输入共两行,第一行为一个整数N,N表示物品的个数,1<=N<=100000.第二行为N个用空格隔开的正整数,表示N个物品最初排列的编号. Output 输出共一行,N个用空格隔开的正整数P1,P2,P3