5016: [Snoi2017]一个简单的询问
Time Limit: 30 Sec Memory Limit: 512 MBSubmit: 87 Solved: 64
[ Submit][ Status][ Discuss]
Description
给你一个长度为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 Input
5
1 1 1 1 1
2
1 2 3 4
1 1 4 4
Sample Output
4
1
把每个问题拆成四个问题,这样就可以O(1)转,直接莫队吧
#include<stdio.h>
#include<math.h>
#include<algorithm>
using namespace std;
#define LL long long
int pos[50005];
typedef struct Que
{
int l, r;
int c, id;
bool operator < (const Que &b) const
{
if(pos[l]<pos[b.l] || pos[l]==pos[b.l] && r<b.r)
return 1;
return 0;
}
}Que;
Que s[200005];
int a[50005];
LL ans[50005], sl[50005], sr[50005];
int main(void)
{
LL val;
int B, cnt, n, q, i, l1, l2, r1, r2, L, R;
scanf("%d", &n);
for(i=1;i<=n;i++)
scanf("%d", &a[i]);
B = sqrt(1.0*n)+1, cnt = 0;
scanf("%d", &q);
for(i=1;i<=q;i++)
{
scanf("%d%d%d%d", &l1, &r1, &l2, &r2);
s[++cnt].id = i, s[cnt].c = 1, s[cnt].l = r1, s[cnt].r = r2;
s[++cnt].id = i, s[cnt].c = 1, s[cnt].l = l1-1, s[cnt].r = l2-1;
s[++cnt].id = i, s[cnt].c = -1, s[cnt].l = l1-1, s[cnt].r = r2;
s[++cnt].id = i, s[cnt].c = -1, s[cnt].l = l2-1, s[cnt].r = r1;
}
R = 1, L = 0;
for(i=1;i<=n;i++)
{
L++;
pos[i] = R;
if(L==B)
R++, L = 0;
}
val = L = R = 0;
sort(s+1, s+cnt+1);
for(i=1;i<=cnt;i++)
{
while(L<s[i].l)
val += sr[a[++L]], sl[a[L]]++;
while(L>s[i].l)
val -= sr[a[L]], sl[a[L--]]--;
while(R<s[i].r)
val += sl[a[++R]], sr[a[R]]++;
while(R>s[i].r)
val -= sl[a[R]], sr[a[R--]]--;
ans[s[i].id] += val*s[i].c;
}
for(i=1;i<=q;i++)
printf("%lld\n", ans[i]);
return 0;
}
/*
5
1 1 1 1 1
7
1 5 1 5
2 2 1 1
2 4 3 5
1 3 2 4
1 3 3 5
1 4 2 5
1 5 5 5
*/