【BZOJ5016】[Snoi2017]一个简单的询问 莫队

【BZOJ5016】[Snoi2017]一个简单的询问

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

题解:先将询问的l--,然后我们开始推式子喽!为了方便起见,下面用s(i)表示get(1,i,x)。那么:

$ans=\sum\limits_{x}(s(r1)-s(l1))*(s(r2)-s(l2)))\\=\sum\limits_{x}s(r1)*s(r2)+s(l1)*s(l2)-s(l1)*s(r2)-s(r1)*s(l2)\\*ab={(a+b)^2-a^2-b^2\over 2}*\\=\sum\limits_{x}{(s(r1)^2+s(r2)^2-(s(r2)-s(r1)))^2+s(l1)^2+s(l2)^2-(s(l2)-s(l1))^2+(s(r2)-s(l1))^2-s(r2)^2-s(l1)^2+(s(r1)-s(l2))^2-s(r1)^2-s(l2)^2\over 2}\\=\sum\limits_{x}{(s(r1)-s(l2))^2+(s(r2)-s(l1))^2-(s(l2)-s(l1))^2-(s(r2)-s(r1))^2\over 2}$

然后用莫队处理区间中每个数出现次数的平方即可!

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <cmath>
using namespace std;
typedef long long ll;
const int maxn=50010;
struct node
{
	int a,b,org,k;
	node() {}
	node(int x,int y,int c,int d){a=min(x,y)+1,b=max(x,y),org=c,k=d;}
}q[maxn<<2];
int s[maxn],v[maxn];
int n,m,B;
ll sum,ans[maxn];
inline int rd()
{
	int ret=0,f=1;	char gc=getchar();
	while(gc<‘0‘||gc>‘9‘)	{if(gc==‘-‘)f=-f;	gc=getchar();}
	while(gc>=‘0‘&&gc<=‘9‘)	ret=ret*10+gc-‘0‘,gc=getchar();
	return ret*f;
}
bool cmp(node a,node b)
{
	return (a.a/B==b.a/B)?(a.b<b.b):(a.a/B<b.a/B);
}
int main()
{
	n=rd(),B=int(sqrt(double(n)));
	int i,a,b,c,d,l,r;
	for(i=1;i<=n;i++)	v[i]=rd();
	m=rd();
	for(i=1;i<=m;i++)	a=rd()-1,b=rd(),c=rd()-1,d=rd(),
		q[i]=node(a,c,i,-1),q[i+m]=node(b,d,i,-1),q[i+2*m]=node(a,d,i,1),q[i+3*m]=node(b,c,i,1);
	sort(q+1,q+4*m+1,cmp);
	for(l=1,r=0,i=1;i<=4*m;i++)
	{
		while(l>q[i].a)	l--,s[v[l]]++,sum+=2*s[v[l]]-1;
		while(l<q[i].a)	sum-=2*s[v[l]]-1,s[v[l]]--,l++;
		while(r<q[i].b)	r++,s[v[r]]++,sum+=2*s[v[r]]-1;
		while(r>q[i].b)	sum-=2*s[v[r]]-1,s[v[r]]--,r--;
		ans[q[i].org]+=q[i].k*sum;
	}
	for(i=1;i<=m;i++)	printf("%lld\n",ans[i]>>1);
	return 0;
}
时间: 2024-10-18 22:10:56

【BZOJ5016】[Snoi2017]一个简单的询问 莫队的相关文章

【bzoj5016】[Snoi2017]一个简单的询问 莫队算法

题目描述 给你一个长度为N的序列ai,1≤i≤N和q组询问,每组询问读入l1,r1,l2,r2,需输出 get(l,r,x)表示计算区间[l,r]中,数字x出现了多少次. 输入 第一行,一个数字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的最大值 输出 对于每组询问,输出一行一个数字,表

bzoj5016 [Snoi2017]一个简单的询问

传送门 分析 我们发现可以通过容斥得到Ans = sum(1,R1,1,R2) - sum(1,R1,1,L2-1) - sum(1,L1-1,1,R2) + sum(1,L1-1,L2-1) 于是我们可以吧一个询问分成4部分 然后进行莫队即可 代码 #include<iostream> #include<cstdio> #include<cstring> #include<string> #include<algorithm> #include

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

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≤50000N1≤ai≤N1≤l1≤r1≤N1≤l2≤r2≤N注意:答案有可能超过int的最大值Output 对于每组询问,输出一行一

【LOJ2254】SNOI2017一个简单的询问

莫队,每次询问的是两个区间,就把区间拆开,分开来算就好了. 借鉴了rank1大佬的玄学排询问的姿势. #include<bits/stdc++.h> #define N 50010 typedef long long ll; using namespace std; inline int read(){ int f=1,x=0;char ch; do{ch=getchar();if(ch=='-')f=-1;}while(ch<'0'||ch>'9'); do{x=x*10+ch-

[Snoi2017]一个简单的询问

数据范围很容易让人想到莫队算法 但是对于每次询问有\(l_1,r_1,l_2,r_2\)四个参数 很不方便维护 所以可以将询问差分 \(get(l,r,x)=get(1,r,x)-get(1,l-1,x)\) \(get(l_1,r_1,x)*get(l_2,r_2,x)\) \(=get(1,r_1,x)*get(1,r_2,x)\) \(-get(1,l_1-1,x)*get(1,r_2,x)\) \(-get(1,r_1,x)*get(1,l_2-1,x)\) \(+get(1,l_1-1

[BZOJ5016]一个简单的询问

给你一个长度为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 对于每组询问,输出一行一个数字

luoguP2709 小B的询问 [莫队]

题目描述 小B有一个序列,包含N个1~K之间的整数.他一共有M个询问,每个询问给定一个区间[L..R],求Sigma(c(i)^2)的值,其中i的值从1到K,其中c(i)表示数字i在[L..R]中的重复次数.小B请你帮助他回答询问. 输入输出格式 输入格式: 第一行,三个整数N.M.K. 第二行,N个整数,表示小B的序列. 接下来的M行,每行两个整数L.R. 输出格式: M行,每行一个整数,其中第i行的整数表示第i个询问的答案. 输入输出样例 输入样例#1: 6 4 3 1 3 2 1 1 3

BZOJ 3781 小B的询问 莫队算法

题目大意:一共有M个询问,每个询问给定一个区间[L..R],求Sigma(c(i)^2)的值,其中i的值从1到K,其中c(i)表示数字i在[L..R]中的重复次数. 思路:莫队走起. CODE: #include <cmath> #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #define MAX 50010 using namespac

[BZOJ3781][P2709]小B的询问[莫队]

入门题 对于一个区间的询问,如果在已知\([l,r]\)的答案时可以用O(1)的时间求出左右端点\(±1\)的答案,就可以使用莫队来优化. 设已知区间为\([l_1,r_1]\),所求区间为\([l_2,r_2]\) 可知求得\([l_2,r_2]\)的成本是\(|l_1-l_2| + |r_1-r_2|\)如果把这两个区间看成点,这个成本就是两点的曼哈顿距离, 对于多个询问,求出曼哈顿距离最小生成树就可以以最小成本获得答案,使用一种奇怪的方式 --sort来获得最优的转移方式 我并不知道原理