【BZOJ3809】Gty的二逼妹子序列 莫队 分块

题目描述

  给你一个长度为\(n\)的数列,还有\(m\)个询问,对于每个询问\((l,r,a,b)\),输出区间\([l,r]\)有多少范围在\([a,b]\)的权值。

  \(n\leq 100000,m\leq 1000000\)

题外话

  Q:这道题和BZOJ3809有什么区别呢?

  A:卡空间。

题解

  考虑莫队。

  每次转移时如果用树状数组很明显会TLE。所以要分块。

  每\(\sqrt n\)个数分一块。这样转移是\(O(1)\)的,查询是\(O(\sqrt n)\)的。

  时间复杂度:\(O(n\sqrt m+m\sqrt n)\)

代码

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cstdlib>
#include<ctime>
#include<utility>
#include<cmath>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int> pii;
typedef pair<ll,ll> pll;
void sort(int &a,int &b)
{
	if(a>b)
		swap(a,b);
}
void open(const char *s)
{
#ifdef DEBUG
	char str[100];
	sprintf(str,"%s.in",s);
	freopen(str,"r",stdin);
	sprintf(str,"%s.out",s);
	freopen(str,"w",stdout);
#endif
}
int sz1,sz2;
//sz1=sqrt(n)
//sz2=n/sqrt(m)
int b1(int x)
{
	return (x+sz1-1)/sz1;
}
int b2(int x)
{
	return (x+sz2-1)/sz2;
}
namespace orzzjt
{
	int a[100010];
	int b[100010];
	void change(int x,int v)
	{
		a[x]+=v;
		b[b1(x)]+=v;
	}
	int query(int x,int y)
	{
		int s=0;
		int i;
		int bx=b1(x);
		int by=b1(y);
		if(bx==by)
		{
			for(i=x;i<=y;i++)
				s+=a[i];
		}
		else
		{
			for(i=x;i<=bx*sz1;i++)
				s+=a[i];
			for(i=(by-1)*sz1+1;i<=y;i++)
				s+=a[i];
			for(i=bx+1;i<=by-1;i++)
				s+=b[i];
		}
		return s;
	}
}
struct ques
{
	int l,r,a,b,id;
};
ques b[1000010];
int cmp(ques a,ques b)
{
	if(b2(a.l)!=b2(b.l))
		return b2(a.l)<b2(b.l);
	return a.r<b.r;
}
int a[100010];
int ans[1000010];
int c[100010];
void add(int x)
{
	c[x]++;
	if(c[x]==1)
		orzzjt::change(x,1);
}
void del(int x)
{
	c[x]--;
	if(!c[x])
		orzzjt::change(x,-1);
}
int main()
{
	int n,m;
	scanf("%d%d",&n,&m);
	sz1=sqrt(n);
	sz2=n/sqrt(m);
	sz2=max(sz2,1);
	int i;
	for(i=1;i<=n;i++)
		scanf("%d",&a[i]);
	for(i=1;i<=m;i++)
	{
		scanf("%d%d%d%d",&b[i].l,&b[i].r,&b[i].a,&b[i].b);
		b[i].id=i;
	}
	sort(b+1,b+m+1,cmp);
	int l=1,r=0;
	for(i=1;i<=m;i++)
	{
		while(r<b[i].r)
			add(a[++r]);
		while(l>b[i].l)
			add(a[--l]);
		while(r>b[i].r)
			del(a[r--]);
		while(l<b[i].l)
			del(a[l++]);
		ans[b[i].id]=orzzjt::query(b[i].a,b[i].b);
	}
	for(i=1;i<=m;i++)
		printf("%d\n",ans[i]);
	return 0;
}
posted @ 2018-03-06 11:11  ywwyww  阅读(106)  评论(0编辑  收藏  举报