任意门: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
Input
Output
q行,每行一个正整数,表示Mato这天需要交换的次数。
Sample Input
1 4 2 3
2
1 2
2 4
Sample Output
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 }
345



被折叠的 条评论
为什么被折叠?



