其他分享
首页 > 其他分享> > [Violet]蒲公英

[Violet]蒲公英

作者:互联网

[Violet]蒲公英

强制在线求区间众数。

思路

与一些分块题不同,本题并没有在块内插入其他东西进行维护,最朴素的分块。类似【作诗】的预处理,预先处理出每个数出现的块后缀和(前缀和应该也没有问题),以及块间的众数。对于[l,r]位于的块是挨着或在同一块的情况,直接暴力处理(挨着的不太好处理),其余的按照分块的正常思路进行。显然,[l,r]的众数一定是整块的众数或者散块中出现的数。注意细节:要输出的是离散化前的编号,以及这里是后缀和,别还原成了前缀和。

代码

memset又一次拖慢近5倍。

inline void INIT()
{
	len = sqrt(n);t = n / len;
	for(int i = 1;i <= t;i++){
		L[i] = (i - 1) * len + 1;
		R[i] = i * len;
	}
	R[t] = n;
	block[n + 1] = n + 1;
	for(int i = 1;i <= t;i++)
	   for(int j = L[i];j <= R[i];j++) block[j] = i;
	for(int i = 1;i <= t;i++){
		int mx = 0;
		for(int j = L[i];j <= n;j++){
			cnt[i][a[j]]++;
			if(cnt[i][mx] < cnt[i][a[j]] || (cnt[i][mx] == cnt[i][a[j]] && a[j] < mx)) mx = a[j];
			if(block[j] != block[j + 1]) res[i][block[j]] = mx;
		}
	}	
}

signed main()
{
	n = read();m = read();
	for(int i = 1;i <= n;i++) a[i] = read(),b[i] = a[i];
	sort(b + 1,b + 1 + n);
	tot = unique(b + 1,b + 1 + n) - b - 1;
	for(int i = 1;i <= n;i++) a[i] = lower_bound(b + 1,b + 1 + tot,a[i]) - b;
	INIT();
	
	while(m--)
	{
		LL l,r;ans = 0;
		scanf("%lld%lld",&l,&r);
		l = (l + lstans - 1) % n + 1,r = (r + lstans - 1) % n + 1;
		if(l > r) swap(l,r);
		if(block[l] + 1 >= block[r]){
			for(int i = l;i <= r;i++){
				num[a[i]]++;
				if(num[ans] < num[a[i]] || (num[ans] == num[a[i]] && a[i] < ans)) ans = a[i];
			}
			lstans = b[ans];
			write(lstans);putchar('\n');
			for(int i = l;i <= r;i++) num[a[i]]--;
			
			continue;
		}
		ans = res[block[l] + 1][block[r] - 1];
		int all = cnt[block[l] + 1][ans] - cnt[block[r]][ans];
		for(int i = l;i <= R[block[l]];i++){
			num[a[i]]++;
			if(num[ans] + all < num[a[i]] + cnt[block[l] + 1][a[i]] - cnt[block[r]][a[i]] || 
			  (num[ans] + all == num[a[i]] + cnt[block[l] + 1][a[i]] - cnt[block[r]][a[i]] && a[i] < ans)) 
			    ans = a[i],all = cnt[block[l] + 1][a[i]] - cnt[block[r]][a[i]];
		}
		for(int i = L[block[r]];i <= r;i++){
			num[a[i]]++;
			if(num[ans] + all < num[a[i]] + cnt[block[l] + 1][a[i]] - cnt[block[r]][a[i]] || 
			  (num[ans] + all == num[a[i]] + cnt[block[l] + 1][a[i]] - cnt[block[r]][a[i]] && a[i] < ans)) 
			    ans = a[i],all = cnt[block[l] + 1][a[i]] - cnt[block[r]][a[i]];
		}
		lstans = b[ans];
		write(lstans);putchar('\n');
		
		for(int i = l;i <= R[block[l]];i++) num[a[i]]--;
		for(int i = L[block[r]];i <= r;i++) num[a[i]]--;
	}
	return 0;
}

标签:分块,int,Violet,len,众数,蒲公英,block
来源: https://www.cnblogs.com/shijiazhuang-li/p/15244432.html