思路:对n个数用结构体数组保存,记录值和次序id
struct node{ int num,id; }a[MAX_];
对m个查询用结构体数组保存,记录左右(L,R)及H以及次序id
struct point { int L,R,id,value; }b[MAX_];以num值从小到大排序,以value值从小到大排序。
然后从排好序的第一个询问和排好序的num值的第一个开始,若是小于第一个询问的value的num,则将其id全部放入树状数组,直到大于该value值时
for(int q = 0, k = 0; q < m; ++q){ while(k < n && b[q].value >= a[k].num){ add(a[k].id,1); k++; } ans[b[q].id] = sum(b[q].R) - sum(b[q].L-1); }
原理即是离散化,然后对id进行树状数组,保证了不会影响后续的值的正确性,又保证了时间复杂度,很是巧妙
代码:
#include <iostream> #include <stdio.h> #include <string.h> #include <math.h> #include <stdlib.h> #include <map> #include <set> #include <vector> #include <stack> #include <algorithm> using namespace std; #define mst(a,b) memset(a,b,sizeof(a)) #define eps 10e-8 const int MAX_ = 100010; const int INF = 0x7fffffff; const int MAX = 100010; struct point { int L,R,id,value; } b[MAX_]; struct node { int num,id; } a[MAX_]; int C[MAX_], ans[MAX_]; int T, n, m,l ,r; int lowbit(int x) { return x&(-x); } void add(int x,int num) { while(x < MAX) { C[x] += num; x += lowbit(x); } } int sum(int x) { int cnt = 0; while(x > 0) { cnt += C[x]; x -= lowbit(x); } return cnt; } bool cmp1(const point &a, const point &b) { return a.value < b.value; } bool cmp2(const node &a,const node& b) { return a.num < b.num; } int main() { int Case = 0; scanf("%d",&T); while(T--) { scanf("%d%d",&n,&m); for(int i = 0; i < n; ++i) { scanf("%d",&a[i].num); a[i].id = i+1; } for(int i = 0; i < m; ++i) { scanf("%d%d%d",&l,&r,&b[i].value); b[i].L = l + 1; b[i].R = r + 1; b[i].id = i ; } sort(a,a+n,cmp2); sort(b,b+m,cmp1); mst(C,0); mst(ans,0); for(int q = 0, k = 0; q < m; ++q) { while(k < n && b[q].value >= a[k].num) { add(a[k].id,1); k++; } ans[b[q].id] = sum(b[q].R) - sum(b[q].L-1); } printf("Case %d:\n",++Case); for(int i = 0; i < m; ++i) { printf("%d\n",ans[i]); } } return 0; }