bzoj 4320: ShangHai2006 Homework【分块】

按根号300000=m分情况讨论
查询是,当x小于等于m,那么可以暴力记录直接出解;否则,用分块维护区间值,查询的时候以x为步长跳根号m次取最小值即可
还有一种并查集方法,来自https://www.cnblogs.com/CQzhangyu/p/7088337.html

#include<iostream>
#include<cstdio>
using namespace std;
const int N=300010,M=550;
int n=300000,m=n/M,q,i,x,bl[N],s[M],f[N],tg[M],g[M];
char op[5];
int main()
{
	for(int i=1;i<=n;i++)
		bl[i]=i/M;
	for(int i=n;i;i--)
		s[bl[i]]=i;
	for(int i=1;i<=n;i++)
		f[i]=N;
	for(int i=0;i<=m;i++)
		tg[i]=N;
	for(int i=1;i<M;i++)
		g[i]=N;
	scanf("%d",&q);
	while(q--)
	{
		scanf("%s%d",op,&x);
		if(op[0]=='A')
		{
			for(int i=1;i<M;i++)
				g[i]=min(g[i],x%i);
			for(int i=s[bl[x]];i<=x;i++)
				f[i]=min(f[i],x);
			for(int i=bl[x]-1;i>=0;i--)
				tg[i]=min(tg[i],x);
		}
		else 
		{
			if(x<M)
				printf("%d
",g[x]);
			else
			{
				int t=N;
				for(int i=0,j=x;i<=n;i=j,j+=x)
				{
					if(j>n)
						j=n+1;
					int y=min(f[max(1,i)],tg[bl[max(1,i)]]);
					if(y<j)
						t=min(t,y-i);
				}
				printf("%d
",t);
			}
		}
	}
	return 0;
}
原文地址:https://www.cnblogs.com/lokiii/p/9651893.html