2017-04-04 水题信心 02Mato 的文件管理
2017-04-04 21:06
295 查看
Description
同学从各路神犇以各种方式(你们懂的)收集了许多资料,这些资料一共有n 份,每份有一个大小和一个编号。为了防止他人偷拷,这些资料都是加密过的,只能用 Mato 自己写的程序才能访问。Mato 每天随机选一个区间[l,r],他今天就看编号在此区间内的这些资料。Mato 有一个习惯,他总是从文件大小从小到大看资料。他先把要看的文件按编号顺序依次拷贝出来,再用他写的排序程序给文件大小排序。排序程序可以在 1 单位时间内交换 2 个相邻的文件(因为加密需要,不能随机访问)。Mato 想要使文件交换次数最小,你能告诉他每天需要交换多少次吗?Input
第一行一个正整数 n,表示 Mato 的资料份数。第二行由空格隔开的 n 个正整数,第 i 个表示编号为 i 的资料的大小。
第三行一个正整数 q,表示 Mato 会看几天资料。
之后 q 行每行两个正整数 l、r,表示 Mato 这天看[l,r]区间的文件。
Output
q 行,每行一个正整数,表示 Mato 这天需要交换的次数。Sample Input
41 4 2 3
2
1 2
2 4
Sample Output
02
Hint
n,q <= 50000样例解释:第一天,Mato 不需要交换
第二天,Mato 可以把 2 号交换 2 次移到最后。
题解
莫队算法。每天需要交换的次数就是区间逆序对的数量,从后面加入/删去一个数,产生/减少的逆序对数目就是前面比它大的元素个数,从前面加入/删去就是后面比它小的元素的个数。这个用树状数组维护就好了。
#include<cmath> #include<cstdio> #include<iostream> #include<algorithm> using namespace std; inline int read(){ int x = 0, f = 1; char c = getchar(); while(!isdigit(c)){ if(c == '-') f = -1; c = getchar(); } while(isdigit(c)){ x = x * 10 + c - '0'; c = getchar(); } return x * f; } const int N = 50000 + 10, M = 50000; struct Query{ int l, r, pl; int ans, id; bool operator < (const Query &rhs) const{ return pl < rhs.pl || (pl == rhs.pl && r < rhs.r); } }q ; int n, m, ans; int a , b , c ; void init(){ n = read(); for(int i = 1; i <= n; i++) a[i] = b[i] = read(); m = read(); int x = sqrt(n); for(int i = 1; i <= m; i++){ q[i].l = read(), q[i].r = read(); q[i].pl = q[i].l / x + 1; q[i].id = i; } sort(q + 1, q + m + 1); sort(b + 1, b + n + 1); b[0] = unique(b + 1, b + n + 1) - b - 1; for(int i = 1; i <= n; i++) a[i] = lower_bound(b+1, b+b[0]+1, a[i]) - b; } bool cmp(Query a, Query b){ return a.id < b.id; } void add(int x, int d){ while(x <= M){ c[x] += d; x += x & -x; } } int sum(int x){ int cnt = 0; while(x){ cnt += c[x]; x -= x & -x; } return cnt; } void opr1(int k, int f){ int tmp = sum(M) - sum(a[k]); add(a[k], f); ans += tmp * f; } void opr2(int k, int f){ int tmp = sum(a[k] - 1); add(a[k], f); ans += tmp * f; } void work(){ for(int i = 1, L = 1, R = 0; i <= m; i++){ for(; R < q[i].r; R++) opr1(R+1, 1); for(; R > q[i].r; R--) opr1(R, -1); for(; L < q[i].l; L++) opr2(L, -1); for(; L > q[i].l; L--) opr2(L-1, 1); q[i].ans = ans; } sort(q + 1, q + m + 1, cmp); for(int i = 1; i <= m; i++) printf("%d\n", q[i].ans); } int main(){ freopen("manager.in", "r", stdin); freopen("manager.out", "w", stdout); init(); work(); return 0; }
相关文章推荐
- 【BZOJ】【P3289】【Mato的文件管理】【题解】【莫队算法】
- BZOJ 3289 Mato的文件管理 莫队算法+树状数组
- 【BZOJ3289】【莫队分块+树状数组求逆序对】Mato的文件管理
- 3289: Mato的文件管理 莫队算法+树状数组
- 系统管理-02 目录和文件管理
- Linux命令工具基础02 文件及目录管理
- Mato的文件管理
- BZOJ 3289 Mato的文件管理 [ 离散化+莫队算法+线段树 ]
- 【bzoj3289】Mato的文件管理
- bzoj3289 Mato的文件管理 莫队算法 树状数组
- BZOJ3289: Mato的文件管理
- BZOJ-3289-Mato的文件管理-莫队+树状数组
- BZOJ-3289 Mato的文件管理
- bzoj 3289: Mato的文件管理 (莫队算法 + 树状数组)
- [BZOJ 3289] Mato的文件管理 · 莫队算法 & 树状数组
- 【莫队算法】bzoj3289 Mato的文件管理
- 【BZOJ 3289】 Mato的文件管理
- 【BZOJ】3289: Mato的文件管理【区间逆序对,莫队套树状数组】
- linux-文件系统管理02-centos7-xfs文件系统
- bzoj3289 : Mato的文件管理