您的位置:首页 > 其它

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

4

1 4 2 3

2

1 2

2 4

Sample Output

0

2

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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: