bzoj 5016: [Snoi2017]一个简单的询问(莫队)

5016: [Snoi2017]一个简单的询问

Time Limit: 30 Sec   Memory Limit: 512 MB
Submit: 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
*/


  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值