4320: ShangHai2006 Homework 并查集+离线处理 思路题

来源:互联网 发布:js 时间戳 时区 编辑:程序博客网 时间:2024/04/27 15:17

好题。。我不会做。。
在我冥思苦想无果的时候发现。。发现。。yzy大神已经A掉了qwq。
果然我这种蒟蒻就该早退役。顺便膜Au爷。


本题分为两种情况讨论。
令M=sqrt(300000).
当Y < M,对所有的插入的数都更新mn[i],暴力就好。。
否则枚举Y的倍数,找第一个比Y的倍数大的数,这个可以用并查集来维护。
因为维护的时候是删除数,所以要离线倒着做。

#include<iostream>#include<cstdio>#include<cstring>using namespace std;int f[300005],num[100005];int mn[605],ans[100005];int n;char opt[100005];inline int read(){    int a=0,f=1; char c=getchar();    while (c<'0'||c>'9') {if (c=='-') f=-1; c=getchar();}    while (c>='0'&&c<='9') {a=a*10+c-'0'; c=getchar();}    return a*f;}int find(int i){    return f[i]==i?i:f[i]=find(f[i]);}int main(){    n=read();    for (int i=1;i<=300000;i++) f[i]=i+1;    memset(mn,127,sizeof(mn));    for (int i=1;i<=n;i++)    {        char s[5];        scanf("%s",s);        opt[i]=s[0];        num[i]=read();        if (opt[i]=='A')        {            for (int j=1;j<=540;j++) mn[j]=min(mn[j],num[i]%j);            f[num[i]]=num[i];        }        else if (num[i]<=540) ans[i]=mn[num[i]];    }    for (int i=n;i;i--)    {        if (opt[i]=='A') f[num[i]]=f[num[i]+1];        else if (num[i]>540)        {            ans[i]=find(1)%num[i];            for (int j=num[i];j<=300000;j+=num[i])            {                int x=find(j);                if (x) ans[i]=min(ans[i],x%num[i]);            }        }    }    for (int i=1;i<=n;i++)         if (opt[i]=='B') printf("%d\n",ans[i]);    return 0;}
0 0
原创粉丝点击