BZOJ 3809 Gty的二逼妹子序列 莫队算法+分块

题目大意:给定一个序列,多次询问[l,r]区间内[a,b]范围内的数有多少

内存28MB,树套树可以歇菜了

首先普通的莫队+树状数组应该都能想到 这样做每次增加/删除一个点是O(logn)的 查询也是O(logn) 时间复杂度O(m√nlogn) 过(bu)不(hao)去(ka)

考虑将树状数组 改成分块 这样虽然查询变成了O(√n) 但是修改变成了O(1)的

这样就把时间复杂度降到了O(m√n) 常数写小点亲测能卡过去

#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define M 100100
using namespace std;
struct query{
	int l,r,a,b,_id;
	bool operator < (const query &x) const;
}queries[1001001];
int n,m,block,l=1,r=0;
int a[M],belong[M],ans[1001001];
int cnt[M],block_cnt[330];
bool query :: operator < (const query &x) const
{
	if( belong[l] != belong[x.l] )
		return l < x.l;
	return r < x.r;
}
namespace IStream{
	const int L=1<<15;
	char buffer[L],*S,*T;
	inline char Get_Char()
	{
		if(S==T)
		{
			T=(S=buffer)+fread(buffer,1,L,stdin);
			if(S==T) return EOF;
		}
		return *S++;
	}
	inline int Get_Int()
	{
		char c;
		int re=0;
		for(c=Get_Char();c<'0'||c>'9';c=Get_Char());
		while(c>='0'&&c<='9')
			re=(re<<1)+(re<<3)+(c-'0'),c=Get_Char();
		return re;
	}
}
class OStream{
	private:
		static const int L=1<<15;
		char stack[20];int top;
		char buffer[L],*S;
	public:
		OStream()
		{
			S=buffer;
		}
		void Put_Int(int x)
		{
			stack[++top]='\n';
			if(!x) stack[++top]='0';
			else while(x)
				stack[++top]=x%10+'0',x/=10;
			while(top)
			{
				if(S==buffer+L-1)
				{
					printf("%s",buffer);
					S=buffer;
				}
				*S++=stack[top--];
			}
		}
		~OStream()
		{
			*S=0;
			puts(buffer);
		}
}os;
inline void Update(int x)
{
	cnt[x]++;
	if(cnt[x]==1)
		block_cnt[belong[x]]++;
}
inline void Downdate(int x)
{
	cnt[x]--;
	if(cnt[x]==0)
		block_cnt[belong[x]]--;
}
int Query(int x,int y)
{
	int i,re=0;
	if(belong[y]-belong[x]<=1)
	{
		for(i=x;i<=y;i++)
			re+=(bool)cnt[i];
		return re;
	}
	for(i=belong[x]+1;i<belong[y];i++)
		re+=block_cnt[i];
	for(i=x;i<=belong[x]*block;i++)
		re+=(bool)cnt[i];
	for(i=y;i>=(belong[y]-1)*block+1;i--)
		re+=(bool)cnt[i];
	return re;
}
int main()
{
	int i;
	cin>>n>>m;
	if(n<=10)
		block=(int)sqrt(n);
	else
		block=(int)sqrt(n);
	for(i=1;i<=n;i++)
	{
		a[i]=IStream::Get_Int();
		belong[i]=(i-1)/block+1;
	}
	for(i=1;i<=m;i++)
	{
		queries[i].l=IStream::Get_Int();
		queries[i].r=IStream::Get_Int();
		queries[i].a=IStream::Get_Int();
		queries[i].b=IStream::Get_Int();
		queries[i]._id=i;
	}
	sort(queries+1,queries+m+1);
	for(i=1;i<=m;i++)
	{
		while(r<queries[i].r)
			Update(a[++r]);
		while(l>queries[i].l)
			Update(a[--l]);
		while(r>queries[i].r)
			Downdate(a[r--]);
		while(l<queries[i].l)
			Downdate(a[l++]);
		ans[queries[i]._id]=Query(queries[i].a,queries[i].b);
	}
	for(i=1;i<=m;i++)
		os.Put_Int(ans[i]);
	return 0;
}


你可能感兴趣的:(分块,bzoj,莫队算法,BZOJ3809)