描述
曾经有一段时间,或许有5年,甚至更长吧。我与木姑娘失去了联系,怎么也联系不上。
那一段日子真的很艰难,我却总是能想起她。
细细数来,从我一声不吭离开,到再次见到她,过去了n天。每天都会不止一次想起她的身影。其中第i天会想起来她ai次。
再次相遇的时候,我向她坦白这一点。她不信。
她给我提出了m个问题,每次都是问我“从第l天到第r天中,有几天你想了我至少k次,却不超过w次?”
格式
输入格式
第一行2个整数n和m(1<=n<=100000,1<=m<=1000000)
之后一行给出n个数a1,a2,…,an
之后m行每行给出4个整数,依次为l,r,k,w
输出格式
输出m行对应m次询问的答案题意:**
在一个长度为n的数组中进行m次询问;
每次询问给出左右端点和上下限,求在这段区间中在上下限中数的个数。
样例
样例输入
10 5
1 2 3 4 1 2 5 3 2 4
1 4 1 3
1 4 1 4
1 4 2 10
1 10 1 2
1 10 1 3
样例输出
3
4
3
5
7
题解:
乍一看,二维树状数组;
再一看,n<=10^5,m<=10^6;
显然二维树状数组是不行的,模拟能拿40分;
我们可以考虑把一个询问拆成两个,分别为1~(l-1)天满足的和1~r天满足的个数;
那么对于每一个询问我们将它和那个日期联系起来,来实现每次我们枚举到一个日期,就可以拿出在这个日期上的询问(就是像邻接表一样);
之后就是枚举日期了,将那个日期中的想念次数加入树状数组中;
所以树状数组一直维护的是1~i天中某区间想念次数的和;
再拿出询问,查询树状数组,保存答案;
然后输出即可。
Tips:
1.a[i]是10^9开不起树状数组,所以要进行离散化缩到10^5
2.巨大的读入要进行读入优化
3.不要用vector存问题,很容易超时
4.存问题的数组要二倍,因为一个拆成了两个
5.询问第l天到第r天就等价于1到r天的答案减去1到l-1天的答案,(用线段树的话可以无视这句话>_<)
←_←就是说好像可以用线段树维护
6. VijosEx 推荐;
#include<stdio.h>
#include<string.h>
#include<algorithm>
#define N 200002
#define M 2000002
using namespace std;
int L[M],R[M],cnt,q[N],no[M],nextq[M];
int n,a[N],dis[N],ans[M],tree[N];
char c;
void get_int(int &x)
{
c=getchar();
while(c==' '||c=='\n')
{
c=getchar();
}
x=c-'0';
while((c=getchar())!=' '&&c!='\n')
{
x=x*10+c-'0';
}
}
void push(int l,int r,int t,int num)
{
L[++cnt]=l;
R[cnt]=r;
no[cnt]=num;
nextq[cnt]=q[t];
q[t]=cnt;
}
int cmp(int a,int b)
{
return a<b;
}
void add(int k)
{
tree[k]++;
do
{
k+=k&(-k);
tree[k]++;
}while(k<=n);
}
int getsum(int k)
{
int ret=0;
while(k)
{
ret+=tree[k];
k-=k&(-k);
}
return ret;
}
int main()
{
int m,len,i,j,k,l,r,st,en;
scanf("%d%d",&n,&m);
for(i=1;i<=n;i++)
{
get_int(a[i]);
dis[i]=a[i];
}
sort(dis+1,dis+1+n,cmp);
len=unique(dis+1,dis+1+n)-dis-1;
for(i=1;i<=m;i++)
{
get_int(st);
get_int(en);
get_int(l);
get_int(r);
if(st>en) swap(st,en);
if(l>r) swap(l,r);
push(l,r,st-1,i);
push(l,r,en,i);
}
for(i=1;i<=n;i++)
{
add(lower_bound(dis+1,dis+1+len,a[i])-dis);
for(j=q[i];j;j=nextq[j])
{
l=lower_bound(dis,dis+len+1,L[j])-dis;
r=lower_bound(dis,dis+len+1,R[j])-dis;
if(R[j]<dis[r]) r--;
if(ans[no[j]])
{
ans[no[j]]=getsum(r)-getsum(l-1)-ans[no[j]];
}
else
{
ans[no[j]]=getsum(r)-getsum(l-1);
}
}
}
for(i=1;i<=m;i++)
{
printf("%d\n",ans[i]);
}
return 0;
}