【BZOJ3506】排序机械臂(Splay)

【BZOJ3506】排序机械臂(Splay)

题面

神TMBZOJ没有题面,感谢SYC的题面
洛谷的题面也不错

题解

对于每次旋转的物体
显然可以预处理出来

现在只要模拟旋转操作就行了
至于在哪里放标记的问题
我只在第K大放会鬼。。
所以在Splay里面也放了一次(和LCT一样的)
然而我每次都把排到了正确位置的元素直接给删掉了。。。
所以跑的很慢很慢。。。

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<set>
#include<map>
#include<vector>
#include<queue>
using namespace std;
#define MAX 120000
#define lson (t[x].ch[0])
#define rson (t[x].ch[1])
inline int read()
{
    int x=0,t=1;char ch=getchar();
    while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
    if(ch=='-')t=-1,ch=getchar();
    while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
    return x*t;
}
struct Node
{
    int ch[2],ff;
    int v,size;
    int rev;
}t[MAX];
int root,n;
int S[MAX],top;
void pushup(int x)
{
    if(!x)return;
    t[x].size=t[lson].size+t[rson].size+1;
}
void rotate(int x)
{
    int y=t[x].ff,z=t[y].ff;
    int k=t[y].ch[1]==x;
    if(z)t[z].ch[t[z].ch[1]==y]=x;t[x].ff=z;
    t[y].ch[k]=t[x].ch[k^1];t[t[x].ch[k^1]].ff=y;
    t[x].ch[k^1]=y;t[y].ff=x;
    pushup(y);pushup(x);
}
void putrev(int x)
{
    swap(lson,rson);
    t[x].rev^=1;
}
void pushdown(int x)
{
    if(!t[x].rev)return;
    t[x].rev^=1;
    if(lson)putrev(lson);
    if(rson)putrev(rson);
}
void Splay(int x,int goal)
{
    S[top=1]=x;
    for(int i=x;i!=root;i=t[i].ff)S[++top]=t[i].ff;
    while(top)pushdown(S[top--]);
    while(t[x].ff!=goal)
    {
        int y=t[x].ff,z=t[y].ff;
        if(z!=goal)
            (t[y].ch[1]==x)^(t[z].ch[1]==y)?rotate(x):rotate(y);
        rotate(x);
    }
    if(!goal)root=x;
}
int Build(int l,int r)
{
    if(l>r)return 0;
    int mid=(l+r)>>1;
    t[mid].ch[0]=Build(l,mid-1);
    t[mid].ch[1]=Build(mid+1,r);
    t[t[mid].ch[0]].ff=t[t[mid].ch[1]].ff=mid;
    pushup(mid);
    return mid;
}
int Kth(int k)
{
    int x=root;
    while(233)
    {
        if(t[x].rev)pushdown(x);
        if(t[lson].size+1>=k)
        {
            if(t[lson].size+1==k)return x;
            else x=lson;
        }
        else k-=t[lson].size+1,x=rson;
    }
    return 0;
}
int Rank(int x)//查找x的排名
{
    Splay(x,0);
    return t[lson].size+1;
}
void Delete(int x)//删除节点x
{
    int tt=Rank(x);
    int L=Kth(tt-1);
    int R=Kth(tt+1);
    Splay(L,0);Splay(R,L);
    t[R].ch[0]=0;
    pushup(R);pushup(L);
}
void Outp(int x)
{
    if(lson)Outp(lson);
    printf("%d ",t[x].v);
    if(rson)Outp(rson);
}
pair<int,int> w[MAX];
int main()
{
    t[0].v=1e9;
    n=read();
    for(int i=2;i<=n+1;++i)t[i].v=read(),w[i-1]=make_pair(t[i].v,i);
    sort(&w[1],&w[n+1]);
    t[1].v=t[n+2].v=1e9;
    root=Build(1,n+2);
    for(int i=1;i<=n;++i)
    {
        int pp=w[i].second;
        int gg=Rank(pp);
        printf("%d ",gg-2+i);
        Splay(1,0);
        Splay(pp,1);
        if(t[pp].ch[0])putrev(t[pp].ch[0]);
        Delete(pp);
    }
    return 0;
}
/*
9
1 3 2 3 3 2 1 2 1
*/

原文地址:https://www.cnblogs.com/cjyyb/p/8270714.html

时间: 2024-10-24 20:26:17

【BZOJ3506】排序机械臂(Splay)的相关文章

[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;

BZOJ 3506 CQOI 2014 排序机械臂 Splay

题目大意:给出一个序列,给出一种排序方式,模拟这种排序方式排序,并输出每次找到的节点的位置. 思路:它让你做什么你就做什么,无非就是个Reverse,很简单.注意一下排序的时候权值相等的情况就行了. CODE: #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #define MAX 100010 #define INF 0x3f3f3f3f using

【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次操作

[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\)旋转到根求左子树大小即可,区间翻转用

[bzoj1552][Cerc2007]robotic sort&amp;&amp;[bzoj3506][Cqoi2014]排序机械臂

非常垃圾的一道平衡树,结果被日了一天.很难受嗷嗷嗷 首先不得不说网上的题解让我这个本来就不熟悉平衡树的彩笔很难受--并不好理解. 还好Sinogi大佬非常的神,一眼就切掉了,而且用更加美妙的解法. 题意在操作时,就是第i次把编号为i-1和编号i的后继分别提到根和根的右儿子,根的右儿子的左子树打上翻转标记. 用外部数组记录原来高度第几大的在平衡树中编号是多少.就可以直接操作了. 注意有相同的高度,离散化时直接按高度第一关键字,编号第二关键字就行了. 还有每次splay要把根到当前节点都pushdo

Luogu P3165 [CQOI2014]排序机械臂

先讲一下和这题一起四倍经验的题: Luogu P4402 [Cerc2007]robotic sort 机械排序 SP2059 CERC07S - Robotic Sort UVA1402 Robotic Sort 这题作为一道十分经典的平衡树维护序列的问题,自然是值得一做的了. 写完翻了下题解发现都是写Splay的dalao,少有的暴力FHQ_Treap党还是用指针实现的. 所以这里略微讲解下数组实现的FHQ_Treap好了,感觉写起来比Splay舒服些. 首先我们要抽象化一下题意:给你\(n