BZOJ3809:Gty的二逼妹子序列

浅谈莫队:https://www.cnblogs.com/AKMer/p/10374756.html

题目传送门:https://lydsy.com/JudgeOnline/problem.php?id=3809

用树状数组维护区间内元素个数,直接在树状数组上统计即可。

然后就\(TLE\)了…………

在桶上使用分块科技统计元素就能\(A\)了。

时间复杂度:\(O(n\sqrt{n})\)

空间复杂度:\(O(n)\)

代码如下:

#include <cmath>
#include <cstdio>
#include <algorithm>
using namespace std;
#define low(i) ((i)&(-(i)))

const int maxn=1e5+5,maxm=1e6+5;

int n,m,block;
int num[maxn],bel[maxn],L[320],R[320];

int read() {
	int x=0,f=1;char ch=getchar();
	for(;ch<'0'||ch>'9';ch=getchar())if(ch=='-')f=-1;
	for(;ch>='0'&&ch<='9';ch=getchar())x=x*10+ch-'0';
	return x*f;
}

struct query {
	int l,r,a,b,id,ans;

	bool operator<(const query &a)const {
		if(bel[l]!=bel[a.l])return bel[l]<bel[a.l];
		if(bel[l]&1)return r<a.r;return r>a.r;
	}
}q[maxm];

struct sqrt_technology {
	int sum[320],cnt[maxn];

	void add(int pos,int v) {
		if(cnt[pos]==0&&v==1)sum[bel[pos]]++;
		if(cnt[pos]==1&&v==-1)sum[bel[pos]]--;
		cnt[pos]+=v;
	}

	int query(int l,int r) {
		int res=0;
		if(bel[l]==bel[r]) {
			for(int i=l;i<=r;i++)
				res+=(cnt[i]!=0);
		}
		else {
			for(int i=l;i<=R[bel[l]];i++)
				res+=(cnt[i]!=0);
			for(int i=L[bel[r]];i<=r;i++)
				res+=(cnt[i]!=0);
			for(int i=bel[l]+1;i<bel[r];i++)
				res+=sum[i];
		}
		return res;
	}
}T;

bool cmp(query a,query b) {return a.id<b.id;}

int main() {
	n=read(),m=read(),block=sqrt(n);
	for(int i=1;i<=n;i++) {
		num[i]=read(),bel[i]=(i-1)/block+1;
		if(bel[i]!=bel[i-1])R[bel[i-1]]=i-1,L[bel[i]]=i;
	}R[bel[n]]=n;
	for(int i=1;i<=m;i++) {
		q[i].id=i;
		q[i].l=read(),q[i].r=read();
		q[i].a=read(),q[i].b=read();
	}
	sort(q+1,q+m+1);
	int nowl=1,nowr=0;
	for(int i=1;i<=m;i++) {
		while(nowl<q[i].l)T.add(num[nowl++],-1);
		while(nowl>q[i].l)T.add(num[--nowl],1);
		while(nowr<q[i].r)T.add(num[++nowr],1);
		while(nowr>q[i].r)T.add(num[nowr--],-1);
		q[i].ans=T.query(q[i].a,q[i].b);
	}
	sort(q+1,q+m+1,cmp);
	for(int i=1;i<=m;i++)
		printf("%d\n",q[i].ans);
	return 0;
}
posted @ 2019-02-15 10:07  AKMer  阅读(92)  评论(0编辑  收藏  举报