BZOJ 3289: Mato的文件管理 【莫队 + 树状数组】

任意门:https://www.lydsy.com/JudgeOnline/problem.php?id=3289

3289: Mato的文件管理

Time Limit: 40 Sec  Memory Limit: 128 MB
Submit: 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

Sample Output

0
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 }

 

posted @ 2019-02-18 20:58  莜莫  阅读(394)  评论(0编辑  收藏  举报