Luogu5268 SNOI2017一个简单的询问

Description

link

给定一个长度为 \(n\) 的序列,定义函数 \(get(l,r,x)\)\(x\) 在区间 \([\ l,r\ ]\) 的出现次数

\(m\) 个询问,每个询问给出四个参数 \(l_1,r_1,l_2,r_2\),求出

\[\sum_{x=0}^{\infty} get(l_1,r_1,x)\times get(l_2,r_2,x) \]

Solution

首先我们发现 \(get(l,r,x)\) 这样的函数并不是很好求,而且是乘积

那么我们差分一下:\(get(1,r,x)-get(1,l-1,x)\)

把式子一展开,我们的每个询问就变成了四个类似的从 \(1\) 开始,求区间相关值乘积了

(把 \(get(1,y,x)\) 直接写成 \(get(y,x)\) 了)

\[\sum_{x=0} ^{\infty} get(l_1-1,x)\times get(l_2-1,x)+get(r_1-1,x)\times get(r_2-1,x)-get(l_1-1,x)\times get(r_2,x)-get(r_1,x)\times get(l_2-1,x) \]

直接莫队 \(+\) 贡献统计即可

其实不太像入门题意义下的莫队,就是在统计答案的时候排序优化复杂度的一个方法

Code

#include
using namespace std;
namespace yspm{
	inline int read()
	{
		int res=0,f=1; char k;
		while(!isdigit(k=getchar())) if(k=='-') f=-1;
		while(isdigit(k)) res=res*10+k-'0',k=getchar();
		return res*f;
	}
	const int N=50010;
	int n,T,cnt,a[N],bl[N],block,l,r;
	struct node{
		int l,r,fl,id;
		inline void init(int a,int b,int c,int d){l=a,r=b,fl=c,id=d; return ;}
		bool operator <(const node s) const
		{
			if(bl[l]!=bl[s.l]) return bl[l]q[i].r) swap(q[i].l,q[i].r);
		} sort(q+1,q+cnt+1);
		for(int i=1;i<=cnt;++i)
		{
			while(lq[i].l) del1(a[l]),--l;
			while(rq[i].r) del2(a[r]),--r;
			ans[q[i].id]+=q[i].fl*res;
		}
		for(int i=1;i<=T;++i) printf("%d\n",ans[i]);
		return 0;
	}
}
signed main(){return yspm::main();}

你可能感兴趣的:(Luogu5268 SNOI2017一个简单的询问)