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\n",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\n",t);
            }
        }
    }
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/lokiii/p/9651893.html
今日推荐