給定乙個長度為n的序列, 需要進行n次交換操作. 第i次操作需要將區間[i, pi]進行翻轉, 其中pi表示序列第i小的數字的下標.
特別的, 如果序列中有重複的元素, 則認為在初始序列中下標小的數字更小.
題目中由於涉及到了區間翻轉, 我們應當聯想到是否可以採用==平衡樹==解決該問題.
首先有個疑問, 我們應當如何維護序列? 怎麼來維護序列? (下面描述先不考慮有重複元素的情況)
因為每次我們需要找到序列中第k小的數字, 然後進行區間翻轉. 於是我們考慮兩種維護序列的方式
①如果我們在平衡樹中維護題目中給定的序列, 那麼我們如何找到區間中第k小的數字?
②如果我們在平衡樹中從小到大維護序列值, 那麼又如何實現區間翻轉操作?
我們發現好像找區間第k小的數字和區間翻轉並不能同時得到處理. (可能剛學平衡樹太菜了, 我看網上別的大佬並沒有糾結如何去維護這個序列)(注: 由於本題的特殊性, 是可以一起實現這兩個操作的, 見2021.3更新)
其實冷靜下來分析, 我們必須依靠平衡樹來實現區間翻轉, 因此我們只能採用①的方法來維護這個序列, 而找到區間第k小, 我們需要進行一步思路轉化.
如果單純依靠平衡樹, 來處理這樣的乙個==動態區間第k小數問題, 好像是不可能的. 但是這個題有乙個特點: 第i次操作後,[1, i]區間一定是從小到大排列好的, 而第i + 1次操作時, 我們不妨看成在[i + 1, n]區間找到最小的數字, 這樣乙個上述問題就轉換成了動態區間找最小值==的問題.
那麼對於這樣的乙個問題, 我們可以通過在樹內部維護乙個fmin, 表示當前區間的最小值是多少. 通過遞迴左右子樹的方式, 我們可以在logn的複雜度內找到那個節點.
這樣整個題的思路就十分清晰了. 唯一我們還沒有解決的問題就是, 題目中可能會有重複元素的情況.
其實這個問題解決起來很簡單, 給原來的序列排個序即可, 但是要求採用穩定排序的方式, 最後給原序列每個位置分配乙個新的值即可.
2021.3更新:本次進行**優化, 我們可以通過開乙個額外陣列的方式, 來記錄第i小的值在平衡樹中的節點編號.
這樣 每次操作前, 我們可以把第i小的數字轉到根結點, 然後其左子樹的大小+1便是其所處的位置.
更新**:
#include
#define rep(i, n) for (int i = 1; i <= (n); ++i)
using
namespace std;
typedef
long
long ll;
const
int n =
1e5+
10, inf =
0x3f3f3f3f
;pair<
int,
int> a[n]
;//原序列陣列, 為了保證穩定排序, 所以採用pair
int w[n]
;//用於建樹, 記錄每個位置的初值
struct node
}t[n]
;int root, ind;
void
pushdown
(node& op,
bool flag)
void
pushdown
(int x)
void
pushup
(int x)
void
rotate
(int x)
void
splay
(int x,
int k)if(
!k) root = x;
}int
getk
(int k)
assert(0
);}int
build
(int l,
int r,
int p = root)
intfindmin
(int x)
assert(0
);}int
getnext
(int x)
intmain()
return0;
}
簡單的機械臂設計(Splay樹)
時間限制 2 sec 記憶體限制 32 mb 題目描述 在東秦綜合樓的深處,有實驗室檢查各種材料的機械和電學效能。你受蔡老闆所託為乙個在實驗室中處理樣品的機械人編寫軟體。在傳送帶上有材料樣本,樣品有不同的高度,可能給下乙個處理單元帶來麻煩。為了消除這些麻煩,我們需要把樣品按高度排序到公升序。重新排序...
機械臂5 機械臂連桿及連桿鏈
操作臂可以看出由一系列剛體通過關節連線而成的乙個運動鏈,我們將這些剛體稱為連桿。通過關節將兩個相鄰的連桿連線起來。當兩個剛體之間的相對運動是兩個平面之間的相對滑動時,連線相鄰兩個剛體的運動副稱為低副。在進行操作臂的結構設計時,通常優先選擇僅具有乙個自由度的關節作為連桿的連線方式。大部分操作中包括轉動...
機械臂開發之機械結構
由於經濟不允許,比較昂貴的機械臂沒有接觸過,但是基本的機械結構都是相識的,一般就是用的材料和驅動的方式不一樣,然後我就以我自己用的機械臂來談談。我組裝的機械臂是以舵機作為機械臂的關節進行控制的,接下來以三自由機械臂進行介紹。三自由度機械臂分析 一.關節 這個機械臂擁有三個旋轉關節,底部的旋轉關節jo...