2724: [Violet 6]蒲公英

2724: [Violet 6]蒲公英

Time Limit: 40 Sec   Memory Limit: 512 MB
Submit: 1432   Solved: 483
[ Submit][ Status][ Discuss]

Description

Input

修正一下

l = (l_0 + x - 1) mod n + 1, r = (r_0 + x - 1) mod n + 1

Output

Sample Input

6 3
1 2 3 2 1 2
1 5
3 6
1 5

Sample Output

1
2
1

HINT


修正下:


n <= 40000, m <= 50000

Source

[ Submit][ Status][ Discuss]


分块算法,,GG,一开始想不到
维护每块ans 询问时结合每块内信息???
显然不行,,这玩意你要怎么合并
对于一组询问,[L,R],找到中间那段连续的块,ans 就是由这一段以及左右两边的一点点组成
f[i][j]:第i块到第j块的ans,暴力预处理O(n根号n)
对于一组询问,f[i][j]不一定是ans,,事实上左右两边的东西不好搞
f[i][j]代表中间一大段的ans,,说明它作为ans的可能性很大呀~~
左右两边还多出来一点点,,对于每个数,二分找它在[L,R]出现的次数
事实上,能影响ans也就这根号个数,,,
所以这样做是对的
O(n根号nlogn)
#include<iostream>
#include<cstdio>
#include<queue>
#include<vector>
#include<bitset>
#include<algorithm>
#include<cstring>
#include<map>
#include<stack>
#include<set>
#include<cmath>
#include<ext/pb_ds/priority_queue.hpp>
using namespace std;

const int maxn = 4E4 + 10;
const int maxm = 210;

int n,m,Sqrt,cur = 1,cnt,num[maxn],a[maxn],
	vis[maxn],co[maxn],f[maxm][maxm];

vector <int> v[maxn];

int Lower_bound(int x,int l,int r,int po)
{
	if (l == r) return l;
	int mid = (l + r) >> 1;
	if (po <= v[x][mid]) return Lower_bound(x,l,mid,po);
	else return Lower_bound(x,mid + 1,r,po);
}

int Query(int x,int L,int R)
{
	int Siz = v[x].size() - 1;
	int p1 = Lower_bound(x,0,Siz,L);
	if (v[x][p1] < L) ++p1;
	int p2 = Lower_bound(x,0,Siz,R);
	if (v[x][p2] > R) --p2; 
	return p2 - p1 + 1;
}

int main()
{
	#ifdef DMC
		freopen("DMC.txt","r",stdin);
	#endif
	
	cin >> n >> m; Sqrt = sqrt(n);
	for (int i = 1; i <= n; i++) scanf("%d",&num[i]),a[i] = num[i];
	sort(a + 1,a + n + 1);
	for (int i = 2; i <= n; i++)
		if (a[i] != a[i-1])
			a[++cur] = a[i];
	for (int i = 1; i <= n; i++) {
		num[i] = lower_bound(a + 1,a + cur + 1,num[i]) - a;
		v[num[i]].push_back(i);
	}
	
	int A,B; A = B = 0;
	for (int i = 1; i <= n; i += Sqrt) {
		int R = i + Sqrt - 1,m1,m2 = 0; 
		++A; B = A; ++cnt;
		for (int j = i; j <= n; j++) {
			if (vis[num[j]] != cnt) vis[num[j]] = cnt,co[num[j]] = 0;
			++co[num[j]];
			if (co[num[j]] > m2) m1 = num[j],m2 = co[num[j]];
			else if (co[num[j]] == m2 && m1 > num[j]) m1 = num[j];
			if (j == R) f[A][B] = m1,++B,R += Sqrt;
		}
	}
	
	int Lastans = 0;
	while (m--) {
		int L,R; scanf("%d%d",&L,&R);
		L = (L + Lastans - 1)%n + 1;
		R = (R + Lastans - 1)%n + 1;
		if (L > R) swap(L,R); ++cnt;
		int m1,m2 = 0; 
		if (R - L + 1 <= 2*Sqrt) {
			for (int j = L; j <= R; j++) {
				if (vis[num[j]] != cnt) vis[num[j]] = cnt,co[num[j]] = 0;
				++co[num[j]];
				if (co[num[j]] > m2) m1 = num[j],m2 = co[num[j]];
				else if (co[num[j]] == m2 && m1 > num[j]) m1 = num[j];
			}
			Lastans = a[m1];
			printf("%d\n",Lastans);
			continue;
		}
		A = L/Sqrt + 2;
		if (L % Sqrt == 1 || L % Sqrt == 0) --A;
		B = R/Sqrt;
		m1 = f[A][B],m2 = Query(m1,L,R);
		int k = (A - 1)*Sqrt;
		for (int j = L; j <= k; j++) 
			if (vis[num[j]] != cnt) {
				vis[num[j]] = cnt;
				int now = Query(num[j],L,R);
				if (now > m2) m1 = num[j],m2 = now;
				else if (now == m2 && m1 > num[j]) m1 = num[j];
			}
		if (R % Sqrt != 0) {
			k = B*Sqrt + 1;
			for (int j = k; j <= R; j++) 
				if (vis[num[j]] != cnt) {
					vis[num[j]] = cnt;
					int now = Query(num[j],L,R);
					if (now > m2) m1 = num[j],m2 = now;
					else if (now == m2 && m1 > num[j]) m1 = num[j];
				}
		}
		Lastans = a[m1];
		printf("%d\n",Lastans);
	}
	return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值