一个简单的询问

给你一个长度为N的序列ai,1≤i≤N和q组询问,每组询问读入l1,r1,l2,r2,需输出
get(l,r,x)表示计算区间[l,r]中,数字x出现了多少次。

Input
第一行,一个数字N,表示序列长度。
第二行,N个数字,表示a1~aN
第三行,一个数字Q,表示询问个数。
第4~Q+3行,每行四个数字l1,r1,l2,r2,表示询问。
N,Q≤50000
N1≤ai≤N
1≤l1≤r1≤N
1≤l2≤r2≤N
注意:答案有可能超过int的最大值

Output
对于每组询问,输出一行一个数字,表示答案

Sample Input51 1 1 1 121 2 3 41 1 4 4
Sample Output41Hint

题解:因为题意很容易懂,所以直接说题;

我们可以将关系式变换一下get(l1,r1,x)*get(l2,r2,x)=get(0,r1,x)*get(0,r2,x)+get(0,l1-1,x)*get(0,l2-1,x)+get(l2-1,r2,x)*get(0,l1-1,x)-get(l1-1,r1,x)*get(0,l1-1,x);然后利用莫队算法即可。

AC代码为:

#include<bits/stdc++.h>
using namespace std;
const int maxn=5e4+10;
const int INF=0x3f3f3f3f;


struct node{
int L;
int R;
int Id;
int sign;
} p[4*maxn];


int a[maxn],block,pos[maxn];
long long cnt[maxn],cntc[maxn],num[maxn];


bool cmp(const node &a,const node &b)
{
return pos[a.L]==pos[b.L]? a.R<b.R : pos[a.L]<pos[b.L];
}


int main()
{
int N,M,l1,l2,r1,r2;

while(scanf("%d",&N)!=EOF)
{
long long flag=0;

memset(cnt,0,sizeof(cnt));
memset(cntc,0,sizeof(cntc));

block=sqrt(N);

for(int i=1;i<=N;i++)
{
cin>>a[i];
pos[i]=(i-1)/block+1;
}

cin>>M;
for(int i=1;i<=M;i++)
{
cin>>l1>>r1>>l2>>r2;

p[++flag]=node{r1,r2,i,1};
p[++flag]=node{r2,l1-1,i,-1};
p[++flag]=node{l2-1,r1,i,-1};
p[++flag]=node{l1-1,l2-1,i,1};
}

sort(p+1,p+flag+1,cmp);

int l=0,r=0,ans=0;

for(int i=1;i<=flag;i++)
{
while(l<p[i].L)
{
l++;
ans+=cntc[a[l]];
cnt[a[l]]++;
}
while(l>p[i].L)
{
ans-=cntc[a[l]];
cnt[a[l]]--;
l--;
}
while(r<p[i].R)
{
r++;
ans+=cnt[a[r]];
cntc[a[r]]++;

while(r>p[i].R)
{
ans-=cnt[a[r]];
cntc[a[r]]--;
r--;
}

num[p[i].Id]+=ans*p[i].sign;
}
for(int i=1;i<=M;i++)
cout<<num[i]<<endl;
}

return 0;
}



posted @ 2018-03-20 17:19  StarHai  阅读(294)  评论(0编辑  收藏  举报