首页 > 代码库 > BZOJ 4320 Homework

BZOJ 4320 Homework

首先要想清楚一定是按根号分块。对于<根号的直接记录。>根号的怎么办呢?

设查询的是%y。

那么我们只要找一个0,y,2y,3y.....的lowerbound就好了。而这是根号的。到此总复杂度n√nlogn,无法通过此题。

怎么办呢?可以考虑离线。我们维护并查集,每个点的祖先是在数轴上它的右边第一个出现的数。

那么倒着做就是删数,就可以合并两个集合,就好了。复杂度n√nα(n)。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#define maxn 400500
#define inf 1000000007
using namespace std;
int n,x;char s[5];
int mn[maxn],father[maxn],a[maxn],tot=0,mx[maxn];
struct query
{
    int type,x,ans;
    query (int type,int x,int ans):type(type),x(x),ans(ans) {}
    query () {}
}q[maxn];
int getfather(int x)
{
    if (x!=father[x]) father[x]=getfather(father[x]);
    return father[x];
}
void unionn(int x,int y)
{
    if (y>300000) return;
    int f1=getfather(x),f2=getfather(y);
    if (f1!=f2) father[f1]=f2;
}
int main()
{
    scanf("%d",&n);
    int top=(int)sqrt(300000)+1;
    for (int i=1;i<=top;i++) mn[i]=inf;
    for (int i=1;i<=n;i++)
    {
        mx[i]=mx[i-1];
        scanf("%s",s);scanf("%d",&x);
        if (s[0]==A) q[i]=query(1,x,0);
        else q[i]=query(2,x,0);
        if (s[0]==A)
        {
            for (int j=1;j<=top;j++)
                mn[j]=min(mn[j],x%j);
            a[++tot]=x;mx[i]=max(mx[i],x);
        }
        else if (x<=top) q[i]=query(2,x,mn[x]);
    }
    sort(a+1,a+tot+1);for (int i=1;i<=300000;i++) father[i]=i;
    int p=1;
    for (int i=1;i<=300000;i++)
    {
        if (a[p]<i) p++;
        father[i]=a[p];
    }
    for (int i=n;i>=1;i--)
    {
        if (q[i].type==1) unionn(q[i].x,q[i].x+1);
        else if (q[i].x>top)
        {
            int ret=inf,kr=q[i].x;
            for (int j=q[i].x;j<=mx[i];j+=q[i].x)
            {
                int f=getfather(j);
                ret=min(ret,f%q[i].x);
            }
            ret=min(ret,getfather(1)%q[i].x);
            q[i]=query(2,kr,ret);
        }
    }
    for (int i=1;i<=n;i++)
        if (q[i].type==2) printf("%d\n",q[i].ans);
    return 0;
}

 

BZOJ 4320 Homework