BZOJ 3289: Mato的文件管理 【莫队 + 树状数组】
任意门:https://www.lydsy.com/JudgeOnline/problem.php?id=3289
3289: Mato的文件管理
Time Limit: 40 Sec Memory Limit: 128 MBSubmit: 4917 Solved: 2041
[Submit][Status][Discuss]
Description
Mato同学从各路神犇以各种方式(你们懂的)收集了许多资料,这些资料一共有n份,每份有一个大小和一个编号
。为了防止他人偷拷,这些资料都是加密过的,只能用Mato自己写的程序才能访问。Mato每天随机选一个区间[l,r
],他今天就看编号在此区间内的这些资料。Mato有一个习惯,他总是从文件大小从小到大看资料。他先把要看的
文件按编号顺序依次拷贝出来,再用他写的排序程序给文件大小排序。排序程序可以在1单位时间内交换2个相邻的
文件(因为加密需要,不能随机访问)。Mato想要使文件交换次数最小,你能告诉他每天需要交换多少次吗?
Input
第一行一个正整数n,表示Mato的资料份数。
第二行由空格隔开的n个正整数,第i个表示编号为i的资料的大小。
第三行一个正整数q,表示Mato会看几天资料。
之后q行每行两个正整数l、r,表示Mato这天看[l,r]区间的文件。
n,q <= 50000
Output
q行,每行一个正整数,表示Mato这天需要交换的次数。
Sample Input
4
1 4 2 3
2
1 2
2 4
1 4 2 3
2
1 2
2 4
Sample Output
0
2
//样例解释:第一天,Mato不需要交换
第二天,Mato可以把2号交换2次移到最后。
2
//样例解释:第一天,Mato不需要交换
第二天,Mato可以把2号交换2次移到最后。
题意概括:
其实就是查询区间的逆序数。
解题思路:
首先根据数据范围,可以先对数据进行离散化。
用树状数组维护当前区间出现的数,那么 X 的逆序数就是在 X 之前已存在当前区间的比 X 大的数,通过树状数组这个很容易实现,然后通过莫队离线操作进行区间的转移。
AC code:
1 #include <bits/stdc++.h> 2 #define INF 0x3f3f3f3f 3 #define LL long long 4 using namespace std; 5 const int MAXN = 5e4+10; 6 7 int N, M; 8 struct Query 9 { 10 int l, r, idx; 11 }Q[MAXN]; 12 int unit; 13 int a[MAXN], b[MAXN], ans[MAXN]; 14 int t[MAXN]; 15 int lowbit(int x){return x&(-x);} 16 bool cmp(struct Query a, struct Query b) 17 { 18 int la = a.l/unit, lb = b.l/unit; 19 if(la == lb) return a.r < b.r; 20 return la < lb; 21 } 22 23 void add(int x, int val) 24 { 25 for(int i = x; i < MAXN; i+=lowbit(i)) 26 t[i] += val; 27 } 28 29 int ask(int x) 30 { 31 int res = 0; 32 for(int i = x; i; i-=lowbit(i)) 33 res+=t[i]; 34 return res; 35 } 36 37 void solve() 38 { 39 int L = 1, R = 0, cur = 0; 40 for(int i = 1; i <= M; i++){ 41 while(L < Q[i].l) {cur-=ask(a[L]-1); add(a[L], -1);L++;} 42 while(L > Q[i].l) {cur+=ask(a[L-1] - 1); add(a[L-1], 1); L--;} 43 while(R < Q[i].r) {cur+=R-L+1-ask(a[R+1]); add(a[R+1], 1); R++;} 44 while(R > Q[i].r) {cur-=R-L+1-ask(a[R]); add(a[R], -1); R--;} 45 ans[Q[i].idx] = cur; 46 } 47 48 for(int i = 1; i <= M; i++){ 49 printf("%d\n", ans[i]); 50 } 51 } 52 53 int main() 54 { 55 scanf("%d", &N); 56 unit = sqrt(N); 57 for(int i = 1; i <= N; i++){ scanf("%d", &a[i]); b[i] = a[i];} 58 scanf("%d", &M); 59 for(int i = 1; i <= M; i++){ 60 scanf("%d %d", &Q[i].l, &Q[i].r); 61 Q[i].idx = i; 62 } 63 sort(b+1, b+N+1); //离散化 64 int cnt = unique(b+1, b+1+N)-b-1; 65 for(int i = 1; i <= N; i++){ 66 a[i] = lower_bound(b+1, b+1+cnt, a[i]) - b; 67 } 68 69 sort(Q+1, Q+1+M, cmp); //莫队分区 70 71 solve(); 72 73 return 0; 74 }