树状数组、询问离线排序
我的想法是对询问离线,然后我们容易知道[l,r]的答案等于[1,r]的值减去[1,l-1]的值
所以把每次询问的两个端点都拉出来,标记好是左端点还是右端点,将每个询问的[1,l-1]和[1,r]答案记录下来
最后一次性输出差值即可。
复杂度O( (n+m) * logn)
貌似和大佬的离线有点不同 大佬的做法是顺便把a数组排序了,不过复杂度倒是一样的
#include<bits/stdc++.h> using namespace std; int c[1<<17]; int a[1<<17]; struct node { int id,l,x,flag; }q[1<<18]; int l[1<<17],r[1<<17]; void add(int x,int v){ for(;x<=100000;x+=x&(-x)) c[x]+=v; } int get(int x){ int ans=0; for(;x;x-=x&(-x)) ans+=c[x]; return ans; } int main(){ int n,m;cin>>n>>m; for(int i=1;i<=n;i++) cin>>a[i]; for(int i=1;i<=m;i++){ int x,y,z;cin>>x>>y>>z; q[2*i-1]={i,x-1,z,0};///存询问的原位置、端点、查询值、是左端点还是右端点 左端点在存的时候直接减1 q[2*i]={i,y,z,1};///flag为0表示左端点,1表示右端点 } sort(q+1,q+2*m+1,[](node a,node b){ return a.l<b.l; }); int k=1; for(int i=0;i<=n;i++){///l为1的时候 l-1为0 需要从0开始 if(a[i])add(a[i],1);///不能处理0的情况 需要判断下 while(q[k].l==i&&k<=2*m){ int sum=get(q[k].x); if(q[k].flag==0) l[q[k].id]=sum; else r[q[k].id]=sum; ++k; } } for(int i=1;i<=m;i++) cout<<r[i]-l[i]<<endl; return 0; }