题意:给你n个数,m个查询,对于一个查询问在[a,b]范围内小于c的数有多少个。
有两种做法:1 树状数组离线处理,将输入的n个数按大小排序,也将查询按他们查询的数的大小排序。从小到大到这n个数放进数状数组里,当小于一个查询的c的所有的数都在放进数状数组里面的时候,查询[a,b]范围内有多少个数。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <vector>
#include <algorithm>
using namespace std;
const int N=1e5+5;
struct node
{
int valu,ind;
node(){}
node(int a,int b){valu=a;ind=b;}
bool operator<(const node &b)const
{
return valu<b.valu;
}
};
struct Query
{
int st,ed,valu,ind;
Query(){}
Query(int a,int b,int c,int d){st=a;ed=b;valu=c;ind=d;}
bool operator<(const Query &b)const
{
return valu<b.valu;
}
};
struct BIT
{
int a[N];
int lowbit(int x){return x&(-x);}
void clear() {memset(a,0,sizeof(a));}
void updata(int pos)
{
for(int i=pos;i>0;i-=lowbit(i))
a[i]+=1;
}
int query(int st,int ed)
{
int sum=0;
for(int i=st;i<N;i+=lowbit(i))
sum+=a[i];
for(int i=ed+1;i<N;i+=lowbit(i))
sum-=a[i];
return sum;
}
}bit;
int res[N];
vector<node> data;
vector<Query> op;
int main()
{
int t,t_cnt=0;
scanf("%d",&t);
while(t--)
{
op.clear(); data.clear(); bit.clear();
int n,m,a,b,c;
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
{
scanf("%d",&a);
data.push_back(node(a,i));
}
for(int i=0;i<m;i++)
{
scanf("%d%d%d",&a,&b,&c);
op.push_back(Query(a+1,b+1,c,i));
}
sort(data.begin(),data.end());
sort(op.begin(),op.end());
int ind=0;
for(int i=0;i<(int)data.size();i++)
{
while(ind<(int)op.size()&&op[ind].valu<data[i].valu)
{
res[op[ind].ind]=bit.query(op[ind].st,op[ind].ed);
ind++;
}
bit.updata(data[i].ind);
}
for(int i=ind;i<(int)op.size();i++)
res[op[i].ind]=bit.query(op[i].st,op[i].ed);
printf("Case %d:\n",++t_cnt);
for(int i=0;i<m;i++)
printf("%d\n",res[i]);
}
return 0;
}
第二种做法是划分树。对于每个查询,二分区间里的第k大数,找出大于要查询的c的第一个数的是第k大,那么答案就是这个k-1。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
#define MID(a,b) (a+((b-a)>>1))
const int N=1e5+5;
struct P_Tree
{
int n,order[N];
int valu[20][N],num[20][N];
void init(int len)
{
n=len;
for(int i=0;i<20;i++) valu[i][0]=0,num[i][0]=0;
for(int i=1;i<=n;i++)
{
scanf("%d",&order[i]);
valu[0][i]=order[i];
}
sort(order+1,order+1+n);
build(1,n,0);
}
void build(int lft,int rht,int ind)
{
if(lft==rht) return;
int mid=MID(lft,rht);
int ln=lft,rn=mid+1,same=mid-lft+1;
for(int i=lft;i<=rht;i++)
if(valu[ind][i]<order[mid]) same--;
for(int i=lft;i<=rht;i++)
{
int flag=0;
if((valu[ind][i]<order[mid])||(valu[ind][i]==order[mid]&&same))
{
flag=1;
valu[ind+1][ln++]=valu[ind][i];
if(valu[ind][i]==order[mid]) same--;
}
else valu[ind+1][rn++]=valu[ind][i];
num[ind][i]=num[ind][i-1]+flag;
}
build(lft,mid,ind+1);
build(mid+1,rht,ind+1);
}
int query(int st,int ed,int k,int lft,int rht,int ind)
{
if(k==0) return -1;
if(ed-st+1<k) return (1<<30);
if(lft==rht) return valu[ind][lft];
int mid=MID(lft,rht);
int lx=num[ind][st-1]-num[ind][lft-1];
int ly=num[ind][ed]-num[ind][st-1];
int rx=st-1-lft+1-lx;
int ry=ed-st+1-ly;
if(ly>=k) return query(lft+lx,lft+lx+ly-1,k,lft,mid,ind+1);
else
{
st=mid+1+rx;
ed=mid+1+rx+ry-1;
return query(st,ed,k-ly,mid+1,rht,ind+1);
}
}
}tree;
int main()
{
int t,t_cnt=0;
scanf("%d",&t);
while(t--)
{
int n,m;
scanf("%d%d",&n,&m);
tree.init(n);
printf("Case %d:\n",++t_cnt);
for(int i=0;i<m;i++)
{
int a,b,c;
scanf("%d%d%d",&a,&b,&c);
a++; b++;
int lft=0,rht=b-a+2;
while(lft<rht)
{
int mid=MID(lft,rht);
int ele=tree.query(a,b,mid,1,n,0);
if(ele<=c) lft=mid+1;
else rht=mid;
}
printf("%d\n",lft-1);
}
}
}