洛谷 P4168 [Violet]蒲公英

题目:蒲公英

思路:
分块。
把所有数分成 n \sqrt{n} n 个块,在每个块里分别求解。

代码:

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

#define maxn 40000
#define maxq 200
#define read(x) scanf("%d",&x)

int n,m;
int a[maxn+5];

map<int,int> mp;
int dic[maxn+5],cnt;

int cq,sq;

int p[maxq+5][maxq+5];
int s[maxq+5][maxn+5];

int vis[maxn+5];

int main() {
	read(n),read(m);
	for(int i=1;i<=n;i++) read(a[i]);
	
	for(int i=1;i<=n;i++) mp[a[i]]++;
	for(map<int,int>::iterator it=mp.begin();it!=mp.end();++it) {
		mp[it->first]=++cnt;
		dic[cnt]=it->first;
	}
	
	for(int i=1;i<=n;i++) a[i]=mp[a[i]];
	
	sq=sqrt(n),cq=n/sq+(n%sq!=0);
	
	for(int i=1;i<=cq;i++) {
		for(int j=1;j<=cnt;j++) s[i][j]=s[i-1][j];
		for(int j=(i-1)*sq+1;j<=min(n,i*sq);j++) {
			s[i][a[j]]++;
		}
	}
	
	for(int i=1;i<=cq;i++) {
		for(int k=(i-1)*sq+1;k<=n;k++) {
			int j=1+(k-1)/sq;
			if(k%sq==1) p[i][j]=p[i][j-1];
			vis[a[k]]++;
			if(vis[a[k]]>vis[p[i][j]]||(vis[a[k]]==vis[p[i][j]]&&a[k]<p[i][j])) p[i][j]=a[k];
		}
		memset(vis,0,sizeof(vis));
	}
	
	
	int lst=0;
	
	for(int i=1;i<=m;i++) {
		int x,y,l,r;
		read(x),read(y);
		x=(lst+x-1)%n+1,y=(lst+y-1)%n+1;
		if(x>y) swap(x,y);
		
		l=x-x%sq+sq+1;
		r=y-y%sq;
		
		int L=l/sq+1,R=r/sq;
		
		int t=p[L][R];
		if(L>R) {
			int P=0;
			for(int j=x;j<=y;j++) {
				vis[a[j]]++;
				if(vis[a[j]]>vis[P]||(a[j]<P&&vis[a[j]]==vis[P])) P=a[j];
			}
			memset(vis,0,sizeof(vis));
			printf("%d\n",lst=dic[P]);continue;
		}
		for(int j=x;j<l;j++) {
			s[R][a[j]]++;
			if(s[R][a[j]]-s[L-1][a[j]]>s[R][p[L][R]]-s[L-1][p[L][R]]||(s[R][a[j]]-s[L-1][a[j]]==s[R][p[L][R]]-s[L-1][p[L][R]]&&a[j]<p[L][R])) p[L][R]=a[j];
		}
		for(int j=r+1;j<=y;j++) {
			s[R][a[j]]++;
			if(s[R][a[j]]-s[L-1][a[j]]>s[R][p[L][R]]-s[L-1][p[L][R]]||(s[R][a[j]]-s[L-1][a[j]]==s[R][p[L][R]]-s[L-1][p[L][R]]&&a[j]<p[L][R])) p[L][R]=a[j];
		}
		
		printf("%d\n",lst=dic[p[L][R]]);
		
		for(int j=x;j<l;j++) s[R][a[j]]--;
		for(int j=r+1;j<=y;j++) s[R][a[j]]--;
		p[L][R]=t;
	}
	
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值