[BZOJ2724] [Violet 6]蒲公英

题目链接

BZOJ.

洛谷.

Solution

神仙分块。

首先分成\(\sqrt{n}\)大小的块,先预处理\(sum[i][v]\)表示值为\(v\)的在前\(i\)个块出现了多少次,离散化之后这部分\(O(n\sqrt{n})\)

然后预处理\(f[i][j]\)表示第\(i\)到第\(j\)个块的众数和出现次数,这个处理可以仿照区间\(dp\),假设我们处理好了\(f[i][j-1]\),那么考虑最后一个块的贡献,众数只有可能是前面块的众数或者是后面多出来的数。

那么可以开个桶\(s[i]\)表示值为\(i\)的出现了多少次,那么先用前面处理出来的前缀和把前\(i\sim j-1\)的块统计好,然后枚举第\(j\)个块的所有值,更新\(s[i]\)顺便处理答案。

那么询问也同样的处理,询问可以分成三块,中间的整块和两边的零碎块,整块直接前缀和加预处理出来的\(f\)更新,零碎的枚举所有值。

总复杂度\(O(n\sqrt{n})\)

#include<bits/stdc++.h>
using namespace std;

void read(int &x) {
    x=0;int f=1;char ch=getchar();
    for(;!isdigit(ch);ch=getchar()) if(ch=='-') f=-f;
    for(;isdigit(ch);ch=getchar()) x=x*10+ch-'0';x*=f;
}

void print(int x) {
    if(x<0) putchar('-'),x=-x;
    if(!x) return ;print(x/10),putchar(x%10+48);
}
void write(int x) {if(!x) putchar('0');else print(x);putchar('\n');}

#define lf double
#define ll long long 

const int maxn = 4e4+10;
const int inf = 1e9;
const lf eps = 1e-8;

int f[202][202],h[202][202],g[202][maxn],n,m,v[maxn],R[maxn],s[maxn],st[maxn],ed[maxn],bel[maxn];

int solve(int l,int r) {
	if(bel[l]==bel[r]) {
		int res=0,num=0;
		for(int i=l;i<=r;i++) s[v[i]]=0;
		for(int i=l;i<=r;i++) {
			s[v[i]]++;
			if(s[v[i]]>num||(s[v[i]]==num&&v[i]<res)) num=s[v[i]],res=v[i];
		}return res;
	}
	int res=f[bel[l]+1][bel[r]-1],num=h[bel[l]+1][bel[r]-1];
	for(int i=l;i<=ed[bel[l]];i++) s[v[i]]=0;
	for(int i=st[bel[r]];i<=r;i++) s[v[i]]=0;
    
	for(int i=l;i<=ed[bel[l]];i++)
		if(!s[v[i]]) s[v[i]]=g[bel[r]-1][v[i]]-g[bel[l]][v[i]];
	for(int i=st[bel[r]];i<=r;i++)
		if(!s[v[i]]) s[v[i]]=g[bel[r]-1][v[i]]-g[bel[l]][v[i]];
	
	for(int i=l;i<=ed[bel[l]];i++) {
		s[v[i]]++;
		if(s[v[i]]>num||(s[v[i]]==num&&v[i]<res)) num=s[v[i]],res=v[i];
	}
	for(int i=st[bel[r]];i<=r;i++) {
		s[v[i]]++;
		if(s[v[i]]>num||(s[v[i]]==num&&v[i]<res)) num=s[v[i]],res=v[i];
	}return res;
}

int main() {
	read(n),read(m);int b=ceil(sqrt(n));
	for(int i=1;i<=n;i++) read(v[i]),R[i]=v[i];
	sort(R+1,R+n+1);int M=unique(R+1,R+n+1)-R-1;
	for(int i=1;i<=n;i++) v[i]=lower_bound(R+1,R+M+1,v[i])-R;
	
	for(int i=1;i<=n;i++) bel[i]=(i-1)/b+1;int cnt=bel[n];
	for(int i=1;i<=n;i++) st[bel[i]]=bel[i]==bel[i-1]?st[bel[i-1]]:i;
	for(int i=n;i;i--) ed[bel[i]]=bel[i]==bel[i+1]?ed[bel[i+1]]:i;
	
	for(int i=1;i<=n;i++)
		for(int j=bel[i];j<=cnt;j++) g[j][v[i]]++;
	
	for(int x=1;x<=cnt;x++) {
		int res=0,num=0;
		for(int i=st[x];i<=ed[x];i++) s[v[i]]=0;
		for(int i=st[x];i<=ed[x];i++) {
			s[v[i]]++;
			if(s[v[i]]>num||(s[v[i]]==num&&v[i]<res)) res=v[i],num=s[v[i]];
		}f[x][x]=res,h[x][x]=num;
	}
		
	for(int len=2;len<=cnt;len++) 
		for(int j=1;j<=cnt-len+1;j++) {
			int l=j,r=j+len-1;f[l][r]=f[l][r-1],h[l][r]=h[l][r-1];
			for(int i=st[r];i<=ed[r];i++) s[v[i]]=0;
			for(int i=st[r];i<=ed[r];i++)
				if(!s[v[i]]) s[v[i]]=g[r-1][v[i]]-g[l-1][v[i]];
			for(int i=st[r];i<=ed[r];i++) {
				s[v[i]]++;
				if(s[v[i]]>h[l][r]||(s[v[i]]==h[l][r]&&v[i]<f[l][r])) f[l][r]=v[i],h[l][r]=s[v[i]];
			}
		}
	
	int lstans=0;
	for(int i=1,l,r;i<=m;i++) {
		read(l),read(r);
		l=(l+lstans-1)%n+1,r=(r+lstans-1)%n+1;
		if(l>r) swap(l,r);
		write(lstans=R[solve(l,r)]);
	}
	return 0;
}
posted @ 2019-03-29 11:35  Hyscere  阅读(196)  评论(0编辑  收藏  举报