• BZOJ4320: ShangHai2006 Homework


    Description

      1:在人物集合 S 中加入一个新的程序员,其代号为 X,保证 X 在当前集合中不存在。 
      2:在当前的人物集合中询问程序员的mod Y 最小的值。 (为什么统计这个?因为拯救
    过世界的人太多了,只能取模) 
     

    Input

    第一行为用空格隔开的一个个正整数 N。 
    接下来有 N 行,若该行第一个字符为“A” ,则表示操作 1;若为“B”,表示操作 2; 
    其中 对于 100%的数据:N≤100000, 1≤X,Y≤300000,保证第二行为操作 1。 
     

    Output

    对于操作 2,每行输出一个合法答案。 
     
     

    Sample Input

    5
    A 3
    A 5
    B 6
    A 9
    B 4

    Sample Output

    3
    1

    HINT

    【样例说明】 

      在第三行的操作前,集合里有 3、5 两个代号,此时 mod 6 最小的值是 3 mod 6 = 3; 

      在第五行的操作前,集合里有 3、5、9,此时 mod 4 最小的值是 5 mod 4 = 1; 

    按权值分块,<=sqrt(300000)的答案直接爆算,>sqrt(300000)的答案可以枚举x/Y的整数部分。

    那么问题就是如何快速计算>x的最小的数并带插入。

    注意快速计算>x的最小的数并带删除可以用并查集来做,那么时光倒流一下就行了。

    #include<cstdio>
    #include<cctype>
    #include<queue>
    #include<cmath>
    #include<cstring>
    #include<algorithm>
    #define rep(i,s,t) for(int i=s;i<=t;i++)
    #define dwn(i,s,t) for(int i=s;i>=t;i--)
    #define ren for(int i=first[x];i!=-1;i=next[i])
    using namespace std;
    inline int read() {
        int x=0,f=1;char c=getchar();
        for(;!isdigit(c);c=getchar()) if(c=='-') f=-1;
        for(;isdigit(c);c=getchar()) x=x*10+c-'0';
        return x*f;
    }
    const int maxn=300010;
    const int maxm=100010;
    int pa[maxn],vis[maxn];
    int A[maxm],type[maxm],res[410],ans[maxm];
    inline int findset(int x) {return !pa[x]||x==pa[x]?x:pa[x]=findset(pa[x]);}
    int main() {
        int SIZE=400;
        rep(i,1,SIZE) res[i]=1e9;
        int n=read();
        rep(i,1,n) {
            char s[2];int x;
            scanf("%s%d",s,&x);
            if(s[0]=='A') {
                type[i]=1;vis[x]=1;A[i]=x;
                rep(i,1,SIZE) res[i]=min(res[i],x%i);
            }
            else {
                if(x<=SIZE) ans[i]=res[x];
                else type[i]=2,A[i]=x;
            }
        }
        rep(i,1,300000) if(!vis[i]) pa[i]=i+1;
        dwn(i,n,1) if(type[i]) {
            if(type[i]==1) pa[A[i]]=A[i]+1;
            else {
                ans[i]=1e9;
                for(int j=0;j<=300000;j+=A[i]) {
                    int x=findset(max(1,j));
                    if(x<=300000) ans[i]=min(ans[i],x%A[i]);
                }
            }
        }
        rep(i,1,n) if(type[i]!=1) printf("%d
    ",ans[i]);
        return 0;
    }
    View Code
  • 相关阅读:
    如何查看微信公众号的历史文章(微信订阅号查看历史消息)
    微信服务号有福啦 每月可以微信群发4次
    欲提高微信图文转化率 需学点如何吊胃口
    只需按一下空格键就可以标注 不用众里寻他千百度
    如何让你的微信图文转化率达到300%
    是智能手机推动windows xp系统停止服务吗
    响应式js幻灯片代码一枚
    微信公众平台回复链接可以直接访问,但不能是锚文字链接<a>标签
    如何用腾讯电脑管家备份微信聊天记录
    android版微信5.2.1更新 支持微信聊天记录备份到电脑上
  • 原文地址:https://www.cnblogs.com/wzj-is-a-juruo/p/4986712.html
Copyright © 2020-2023  润新知