给n, m,
给n个数字, 表示位置i的数字的排名,
再给m个询问, 一个询问由a, b组成, 代表着要询问前i个数字中, 排名前b的数目.
当时想了好久好久, 但是一点意识也没有qwq.
后来...看了别人的想法后, 突然就懂了点...
这种问题吧, 我感觉是要先确定一些顺序, 再根据已有的顺序进行操作.
比如这里, 先确定询问的顺序, 把询问依据a排序, 这样的话, 对每一个询问, 可以通过树状数组快速得到答案.
并且这样只增加, 不减少, 时间复杂度为O(nlogn)(n, m是同阶的)
说得不清楚, 还是看代码吧.
#include <iostream>
#include <algorithm>
#include <cstdlib>
#include <cstdio>
#include <cmath>
using namespace std;
const int MAXN = 1e5 + 600;
int bit[MAXN], n, m;
int a[MAXN];
void modify(int i, int v){
while(i <= n){
bit[i] += v;
i += i & -i;
}
}
int query(int i){
int rst = 0;
while(i){
rst += bit[i];
i -= i & -i;
}
return rst;
}
struct Query{
int a, b, c;
bool operator<(const Query & rhs) const{
return a < rhs.a;
}
} queries[MAXN];
int results[MAXN];
int main(){
scanf("%d%d", &n, &m);
for(int i = 1; i <= n; ++i){// 学号从1开始
scanf("%d", a + i);
}
for(int i = 0; i < m; ++i){// 读取询问
scanf("%d%d", &queries[i].a, &queries[i].b);// 注意取地址符...
queries[i].c = i;
}
sort(queries, queries + m);// 离线查询, 排序询问
int cur = 0;// 当前要接受询问的位置, 范围是[0, m)
for(int i = 1; i <= n; ++i){
modify(a[i], 1);
while(cur < m && i == queries[cur].a){// 这个地方慢慢推敲下...要注意cur的范围
results[queries[cur].c] = query(queries[cur].b);
++cur;
}
}
for(int i = 0; i < m; ++i){
printf("%d\n", results[i]);
}
return 0;
}