BZOJ3289 Mato的檔案管理

2022-05-10 05:28:07 字數 1382 閱讀 3265

給你\(n\)個數,\(m\)個詢問

每次詢問一段區間\([l,r]\),可以進行交換相鄰兩個元素的操作,使這段區間從小到大排序的最小操作次數

\(n,m\leq 50000\),元素值在\(1000000\)內,沒有重複元素

這題第一感覺,好像和逆序對有關?

那麼給出性質:

使區間[l,r]按題意方式從小到大排序的最小操作次數等價於區間[l,r]的逆序對總數

這是乙個很強的結論了

嘗試給出證明:

首先證明操作次數的下限是逆序對個數

很顯然,每次操作(交換相鄰兩數)能且至多消除乙個逆序對

因此下限就是逆序對個數

然後我們證明每次操作都可以消除乙個逆序對

同樣很顯然,假設不存在可以消除的逆序對,這意味著這個序列是有序的!

同時,如果序列不是有序的,那麼必定存在一對相鄰的逆序對可以消除

於是我們(類似貪心的)取到了最優方案

於是這題就變成求區間逆序對個數了

那麼考慮用莫隊和權值樹狀陣列求解

所謂權值樹狀陣列,就是維護對應權值出現次數

第i位上的值代表i的出現次數

那麼k的字首和的含義就是不大於k的數一共有幾個

莫隊最核心的就是得到指標移動對答案的影響

我們考慮在末尾增加乙個元素的情況:

那個元素貢獻的逆序對個數就是前面比它大的元素個數

看樣子需要兩個權值樹狀陣列,乙個維護字首和,乙個字尾和?

其實不用,因為比a大的元素個數就是總數-不大於a的元素個數

這個可以直接用權值樹狀陣列維護字首和

複雜度分析,\(blo=\sqrt\)最優

複雜度\(o(n\sqrtlogn)\)

#include#include#include#includeconst int base=230;

int blo[70000];

int n,q;

namespace tarr

inline int lowbit(int k)

void add(int k,int v)

}int query(int k)

return ret;

}}

struct queryq[100000];

bool cmp_q(query x,query y)

while (r>q[i].y)

while (lans[q[i].id]=val;

}for (int i=1;i<=q;i++) printf("%d\n",ans[i]);

}

bzoj3289 Mato的檔案管理

給定乙個序列,每次詢問乙個區間,你可以交換相鄰兩個元素,這個區間你最少需要多少次交換才能使其有序。我們觀察,每次交換如果交換a i 和a i 1 那麼顯然a i a i 1 交換後逆序對個數減一。當序列逆序對個數為0時序列就有序。那麼顯然題意就是詢問區間逆序對個數。我們可以用莫隊演算法來做。因為它符...

bzoj 3289 Mato的檔案管理

description mato同學從各路神犇以各種方式 你們懂的 收集了許多資料,這些資料一共有n份,每份有乙個大小和乙個編號。為了防止他人偷拷,這些資料都是加密過的,只能用mato自己寫的程式才能訪問。mato每天隨機選乙個區間 l,r 他今天就看編號在此區間內的這些資料。mato有乙個習慣,他...

bzoj3289 Mato的檔案管理

description mato同學從各路神犇以各種方式 你們懂的 收集了許多資料,這些資料一共有n份,每份有乙個大小和乙個編號。為了防止他人偷拷,這些資料都是加密過的,只能用mato自己寫的程式才能訪問。mato每天隨機選乙個區間 l,r 他今天就看編號在此區間內的這些資料。mato有乙個習慣,他...