题意:给定一段区间每个点有个高度。在m次询问中每次给出左右端点和可以到达的高度,统计有多少个是小于到达高度
线段树
#include <iostream> #include <algorithm> using namespace std; #define lson l , m , rt << 1 #define rson m + 1 , r , rt << 1 | 1 #define maxn 100001 #define MAXN 100001 int MAX[maxn<<2]; int scan() { int res = 0, ch, flag = 0; if((ch = getchar()) == '-') //判断正负 flag = 1; else if(ch >= '0' && ch <= '9') //得到完整的数 res = ch - '0'; while((ch = getchar()) >= '0' && ch <= '9' ) res = res * 10 + ch - '0'; return flag ? -res : res; } struct Node { int s,t; int h; int index; }node[MAXN]; int answer[MAXN]; struct SS { int index; int v; }nn[MAXN]; void PushUP(int rt) { MAX[rt] = MAX[rt<<1] + MAX[rt<<1|1]; } void build(int l,int r,int rt) { if (l == r) { //scanf("%d",&MAX[rt][0]); MAX[rt]=0; return ; } int m = (l + r) >> 1; build(lson); build(rson); PushUP(rt); } void update(int p,int add,int l,int r,int rt) { if (l == r) { MAX[rt] += add; return ; } int m = (l + r) >> 1; if (p <= m) update(p , add , lson); else update(p , add , rson); PushUP(rt); } int query(int L,int R,int l,int r,int rt) { if (L <= l && r <= R) { return MAX[rt]; } int m = (l + r) >> 1; int ret = 0; //递归调用每回求最值 if (L <= m) ret += query(L , R , lson); if (R > m) ret += query(L , R , rson); return ret; } bool cmp(SS a,SS b) { return a.v<b.v; } bool cmp2(Node a,Node b) { return a.h<b.h; } int main() { int T; int m; int n; int iCase=0; T=scan(); while(T--) { iCase++; n=scan(); m=scan(); //scanf("%d%d",&n,&m); build(1,n,1); for(int i=1;i<=n;i++) { nn[i].v=scan(); //scanf("%d",&nn[i].v); nn[i].index=i; } for(int i=0;i<m;i++) { node[i].s=scan(); node[i].t=scan(); node[i].h=scan(); //scanf("%d%d%d",&node[i].s,&node[i].t,&node[i].h); node[i].s++; node[i].t++; node[i].index=i; } sort(node,node+m,cmp2); sort(nn+1,nn+1+n,cmp); int i,j; i=1; j=0; while(j<m) { while(i<=n) { if(nn[i].v>node[j].h)break; update(nn[i].index,1,1,n,1); i++; } while(j<m) { if(i<=n&&node[j].h>=nn[i].v)break; answer[node[j].index]=query(node[j].s,node[j].t,1,n,1); j++; } } printf("Case %d:\n",iCase); for(int i=0;i<m;i++) printf("%d\n",answer[i]); } return 0; }
树状数组
#include<stdio.h> #include<algorithm> #include<string.h> using namespace std; const int MAXN=100010; int c[MAXN]; int n; int lowbit(int x) { return x&(-x); } void plus(int i,int val) { while(i<=n) { c[i]+=val; i+=lowbit(i); } } int sum(int i) { int s=0; while(i>0) { s+=c[i]; i-=lowbit(i); } return s; } struct Node { int s,t; int h; int index; }node[MAXN]; int answer[MAXN]; struct SS { int index; int v; }nn[MAXN]; bool cmp(SS a,SS b) { return a.v<b.v; } bool cmp2(Node a,Node b) { return a.h<b.h; } int input() { int ret=0; char ch; ch=getchar(); while(ch<'0'||ch>'9')ch=getchar(); while(ch>='0'&&ch<='9') { ret*=10; ret+=ch-'0'; ch=getchar(); } return ret; } int main() { int T; int m; int iCase=0; scanf("%d",&T); //T=input(); while(T--) { iCase++; scanf("%d%d",&n,&m); for(int i=1;i<=n;i++) { scanf("%d",&nn[i].v); //nn[i].v=input(); nn[i].index=i; } for(int i=0;i<m;i++) { scanf("%d%d%d",&node[i].s,&node[i].t,&node[i].h); //node[i].s=input(); //node[i].t=input(); //node[i].h=input(); node[i].s++; node[i].t++; node[i].index=i; //从1开始 所以全部起点终点++ } memset(c,0,sizeof(c)); sort(node,node+m,cmp2); sort(nn+1,nn+1+n,cmp); int i,j; i=1; j=0; while(j<m) { //因为已经排序所以可以直接统计 while(i<=n) { if(nn[i].v>node[j].h)break; plus(nn[i].index,1); i++; } while(j<m) { if(i<=n&&node[j].h>=nn[i].v)break; answer[node[j].index]=sum(node[j].t)-sum(node[j].s-1); j++; /*因为前一次询问(while(i<=n))已经找到满足当前询问满足的最大高度位置为i 下一次询问的H比当前节点的i的值要还要高说明需要找节点i(当前满足条件节点) 之后是否有满足条件的,这样省去了标记每个节点是否需要访问 */ } } printf("Case %d:\n",iCase); for(int i=0;i<m;i++) printf("%d\n",answer[i]); } return 0; }