2018暑期牛客网多校第一场签到题---莫队算法

嗯,一元体验场,让人体验到绝望。听出题人说,这是一套没有签到题的区域赛难度题目。如果有签到题,就是三题铜牌,然后我光荣一道题。算上遥远天国的签到题。嗯光荣两道题打铁。不说感想了。因为比赛是私有的。所以在这里只能分享一下题意题解,和我AC的代码。

题意:给n个数字和q次查询,q次查询包括两个值。l和r,问1到l区间和r到n区间不同的数字个数的。n和q的范围都是1e5.

题解:暴力超时加超内存。嗯,但是稍微改改就是裸的莫队算法。把n个数翻倍,那么原来的l + n 就是r, 原来的r 就是新的l。套莫队的板子即可

看代码

#include<bits/stdc++.h>
using namespace std;
const int maxn = 1e5+5*2;
struct node{
	int lef,rig,id;
}Q[maxn];
int n,s[maxn],pos[maxn],block;
int m;
int Ans[maxn];
int val[maxn];
inline bool cmp(const node & a,const node & b){
	if(pos[a.lef] != pos[b.lef]) return pos[a.lef] < pos[b.lef];
	return pos[a.rig] < pos[b.rig];
}

inline void solve(){
	int lef = 0,rig = 0,ans = 0;
	for(int i = 1; i <= m ; i ++){
		while(lef < Q[i].lef){
			if(--val[s[lef++]] == 0) ans --;
		}
		while(lef > Q[i].lef){
			if(val[s[--lef]]++ == 0) ans ++;
		}
		while(rig < Q[i].rig) {
			if(val[s[++rig]]++ == 0)  ans ++;
		}
		while(rig > Q[i].rig)
			if(--val[s[rig--]] == 0) ans --;
		Ans[Q[i].id] = ans;
	}
	return ;
}
int main(){
	while(~scanf("%d%d",&n,&m)){
		memset(val,0,sizeof(val));
		block = sqrt(n);
		for(int i = 1; i <= n ; i ++){
			scanf("%d",&s[i]);
			s[i+n] = s[i];
		}
		for(int i = 1; i <= n ; i ++)
			pos[i] = (i-1)/block + 1;
		for(int i = 1 ; i <= m ; i ++){
			int a,b;
			scanf("%d%d",&a,&b);
			Q[i].lef = b;
			Q[i].rig = a + n;
			Q[i].id = i;
		}
		sort(Q+1,Q+1+m,cmp);
		solve();
		for(int i = 1; i <= m ; i++){
			printf("%d\n",Ans[i]);
		}
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/pk__pk/article/details/81126917