題目藍鏈
給你乙個長度為\(n\)的序列,你要對它進行操作,規則如下
第\(i\)次操作時,找到區間\([1, n]\)中第\(i\)小的數的位置\(p_i\),並翻轉區間\([i, p_i]\)
最後輸出操作序列\(p_i\)
很久沒有做過\(splay\)的題目了,來打個板子複習一下
我們可以把題意轉換一下:第\(i\)次操作時,找到區間\([i, n]\)中最小的數的位置\(p_i\),並翻轉區間\([i, p_i]\)
然後這相當於就是乙個排序 雖然我沒用這個做法
我的做法特別簡單粗暴,就是照著題意模擬
每次直接找整段區間最小值的位置,然後用\(splay\)模擬題目的翻轉,然後把這個最小值設為\(inf\)
\(p_i\)序列就邊操作邊輸出就可以了
#include using namespace std;
#define fst first
#define snd second
#define mp make_pair
#define squ(x) ((ll)(x) * (x))
#define debug(...) fprintf(stderr, __va_args__)
typedef long long ll;
typedef pairpii;
templateinline bool chkmax(t &a, const t &b)
templateinline bool chkmin(t &a, const t &b)
inline int read()
const int maxn = 1e5 + 10;
const int inf = 1e9;
int n, a[maxn];
namespace splay
}a[maxn];
#define ls(x) a[x].son[0]
#define rs(x) a[x].son[1]
#define fa(x) a[x].f
inline void push_up(int x)
inline void push_down(int x)
} inline bool chk(int x)
inline void link(int x, int y, int f)
inline void rotate(int x)
inline void splay(int x, int y)
if (!y) rt = x; /**/
} inline void build(int &x, int l, int r)
inline int rank(int k)
return x;
} inline void reverse(int x, int y)
inline void change(int x)
inline int query() /**/
x = (a[ls(x)].s < a[rs(x)].s ? ls(x) : (res += a[ls(x)].sz + 1, rs(x)));
} return res + 1; }}
int main()
return 0;
}
排序機械臂 splay
給定乙個長度為n的序列,需要進行n次交換操作.第i次操作需要將區間 i,pi 進行翻轉,其中pi表示序列第i小的數字的下標.特別的,如果序列中有重複的元素,則認為在初始序列中下標小的數字更小.題目中由於涉及到了區間翻轉,我們應當聯想到是否可以採用 平衡樹 解決該問題.首先有個疑問,我們應當如何維護序...
luogu1155 雙棧排序
題目描述 tom最近在研究乙個有趣的排序問題。如圖所示,通過2個棧s1和s2,tom希望借助以下4種操作實現將輸入序列公升序排序。操作a如果輸入序列不為空,將第乙個元素壓入棧s1 操作b如果棧s1不為空,將s1棧頂元素彈出至輸出序列 操作c如果輸入序列不為空,將第乙個元素壓入棧s2 操作d如果棧s2...
LUOGU 3089 字尾排序(模板)
傳送門 這是乙個神奇的演算法,sa i 表示排名第i為的元素是啥,rk i 表示第i個元素排名是啥。然後使用基數排序 倍增的思想去處理。主要是參考的這位大佬的部落格 include include include include using namespace std const int maxn ...