关于(个人认为的)正解分块被卡 T 一个点那些事
查看原帖
关于(个人认为的)正解分块被卡 T 一个点那些事
306748
Zack_zhu楼主2021/6/26 13:37

RTRT ,改吐了,求巨佬们帮蒟蒻看看吧
题目链接

#include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std;
const int MAXN = 4e4+5;
const int MAXQ = 505;
int k[MAXQ][MAXQ],s[MAXQ][MAXN],a[MAXN],lsh[MAXN],l[MAXQ],r[MAXQ],t[MAXN],p[MAXN],pos[MAXN],maxx,now,cnt,n,m,x,y,ans,block;

template <typename T>
inline void read(T &s)
{
	s = 0;
	bool w = false;
	char ch = getchar();
	while(ch < '0'||ch > '9')
	{
		if(ch == '-')
			w = true;
		ch = getchar();
	}
	while(ch >= '0'&&ch <= '9')
	{
		s = (s<<3)+(s<<1)+(ch^48);
		ch = getchar();
	}
	s = w == true ? -s:s;
	return;
}

inline void in_block()
{
	memset(t,0,sizeof(t));
	maxx = 0;
	for(int i = x;i <= y;i++)//暴力扫 
	{
		t[a[i]]++;
		if(t[maxx] < t[a[i]])
			maxx = a[i];
		if(t[maxx] == t[a[i]])
			maxx = min(maxx,a[i]);
	}
	ans = p[maxx];
	return;
}

inline void out_block()
{
	memset(t,0,sizeof(t));
	maxx = 0;
	for(int i = x;i <= r[pos[x]];i++)//暴力查整块左边的 
	{
		t[a[i]]++;
		if(t[maxx] < t[a[i]])
			maxx = a[i];
		if(t[maxx] == t[a[i]])
			maxx = min(maxx,a[i]);
	}
	for(int i = l[pos[y]];i <= y;i++)//暴力查整块右边的 
	{
		t[a[i]]++;
		if(t[maxx] < t[a[i]])
			maxx = a[i];
		if(t[maxx] == t[a[i]])
			maxx = min(maxx,a[i]);
	}
	if(maxx == k[pos[x] + 1][pos[y] - 1])//如果相等,直接还原并返回(BTW:p为离散化前对应的值) 
		ans = p[maxx];
	else
	{
		t[maxx] += s[pos[y] - 1][maxx] - s[pos[x]][maxx];//加上块内的边上求得的众数 
		int ans2 = t[k[pos[x] + 1][pos[y] - 1]] + s[pos[y] - 1][k[pos[x] + 1][pos[y] - 1]] - s[pos[x]][k[pos[x] + 1][pos[y] - 1]];//块内众数的个数 
		if(t[maxx] > ans2)//选择答案 
			ans = p[maxx];
		else if(t[maxx] == ans2)
			ans = p[min(maxx,k[pos[x] + 1][pos[y] - 1])];
		else
			ans = p[k[pos[x] + 1][pos[y] - 1]];
	}
	return;
}

int main()
{
	read(n);
	read(m);
	block = sqrt(n);
	for(int i = 1;i <= n;i++)
	{
		read(a[i]);
		lsh[i] = a[i];
	}
	sort(lsh+1,lsh+1+n);//离散化 
	cnt = unique(lsh+1,lsh+1+n) - lsh - 1;
	for(int i = 1;i <= n;i++)
		now = a[i],a[i] = lower_bound(lsh+1,lsh+1+cnt,a[i]) - lsh,p[a[i]] = now;
	for(int i = 1;i <= block;i++)//预处理左右端点 
	{
		l[i] = (i - 1) * block + 1;
		r[i] = i * block;
	}
	if(r[block] < n)
	{
		l[++block] = r[block - 1] + 1;
		r[block] = n;
	}
	for(int i = 1;i <= block;i++)
		for(int j = l[i];j <= r[i];j++)
			pos[j] = i;//每一个位置对应的块的编号 
	for(int i = 1;i <= block;i++)
	{
		for(int j = 1;j <= cnt;j++)
			s[i][j] += s[i-1][j];//sum数组处理 1 ~ i中j的个数 
		for(int j = l[i];j <= r[i];j++)
			s[i][a[j]]++;
	}		
	for(int i = 1;i <= block;i++)
	{
		memset(t,0,sizeof(t));//开桶记录出现了几次。。。 
		for(int j = i;j <= block;j++)
		{
			k[i][j] = k[i][j-1];//k为在块 i ~ j中的众数 
			for(int z = l[j];z <= r[j];z++)
			{
				t[a[z]]++;
				if(t[k[i][j]] < t[a[z]])
				k[i][j] = a[z];
				if(t[k[i][j]] == t[a[z]])
				k[i][j] = min(k[i][j],a[z]);//暴力预处理 
			}
		}
	}
	ans = 0;
	for(int i = 1;i <= m;i++)
	{
		read(x);
		read(y);
		x = (x + ans - 1) % n + 1;
		y = (y + ans - 1) % n + 1;//还原左右区间 
		if(x > y)
		swap(x,y);
		if(pos[x] - pos[y] <= 1)
			in_block();//在同一块内暴力处理 
		else
			out_block();//不同块分块处理 
		printf("%d\n",ans);
	}
	return 0;
}
2021/6/26 13:37
加载中...