BZOJ4320 ShangHai2006 Homework(分块+并查集)

  考虑根号分块。对于<√3e5的模数,每加入一个数就暴力更新最小值;对于>√3e5的模数,由于最多被分成√3e5块,查询时对每一块找最小值,这用一些正常的DS显然可以做到log,但不太跑得过。考虑并查集在序列上的奇技淫巧。加点不太能做,考虑离线改成删点。并查集维护下一个未删除的点即可。

#include<iostream> 
#include<cstdio>
#include<cmath>
#include<cstdlib>
#include<cstring>
#include<algorithm>
using namespace std;
int read()
{
    int x=0,f=1;char c=getchar();
    while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();}
    while (c>='0'&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar();
    return x*f;
}
#define N 100010
#define M 300000
int m,n,q,a[N],b[N],mn[N],ans[N],fa[N*3];
bool flag[N*3];
const int block=600;
int find(int x){return fa[x]==x?x:fa[x]=find(fa[x]);}
int main()
{
#ifndef ONLINE_JUDGE
    freopen("bzoj4320.in","r",stdin);
    freopen("bzoj4320.out","w",stdout);
    const char LL[]="%I64d\n";
#else
    const char LL[]="%lld\n";
#endif
    m=read();
    for (int i=1;i<=block;i++) mn[i]=i;
    while (m--)
    {
        char c=getchar();while (c!='A'&&c!='B') c=getchar();
        a[++n]=read();
        if (c=='A')
        {
            b[n]=1;flag[a[n]]=1;
            for (int i=1;i<=block;i++)
            mn[i]=min(mn[i],a[n]%i);
        }
        else if (a[n]<=block) ans[n]=mn[a[n]];
    }
    fa[M+1]=M+1;
    for (int i=M;i>=0;i--) if (flag[i]) fa[i]=i;else fa[i]=fa[i+1];
    for (int i=n;i>=1;i--)
    if (b[i]) fa[a[i]]=find(a[i]+1);
    else if (a[i]>block)
    {
        ans[i]=M+1;
        for (int j=0;j<=M;j+=a[i])
        {
            int p=find(j);
            if (p<min(j+a[i],M+1)) ans[i]=min(ans[i],p%a[i]);
        }
    }
    for (int i=1;i<=n;i++) if (!b[i]) printf("%d\n",ans[i]);
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/Gloid/p/9858970.html
今日推荐