給你\(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有乙個習慣,他...