zoukankan      html  css  js  c++  java
  • loj #2048. 「HNOI2016」最小公倍数

    #2048. 「HNOI2016」最小公倍数

    题目描述

    给定一张 N NN 个顶点 M MM 条边的无向图(顶点编号为 1,2,⋯,n 1,2, cdots ,n1,2,,n),每条边上带有权值。所有权值都可以分解成 2a⋅3b 2^a cdot 3^b2a​​3b​​ 的形式。

    现在有 q qq 个询问,每次询问给定四个参数 u uu、v vv、a aa 和 b bb,请你求出是否存在一条顶点 u uu 到 v vv 之间的路径,使得路径依次经过的边上的权值的最小公倍数为 2a⋅3b 2^a cdot 3^b2a​​3b​​ 。

    注意:路径可以不是简单路径。

    下面是一些可能有用的定义:
    最小公倍数: k kk 个数 a1,a2,⋯,ak a_1 , a_2, cdots , a_ka1​​,a2​​,,ak​​ 的最小公倍数是能被每个 aia_iai​​ 整除的最小正整数。
    路径:路径 P:P1,P2,,Pk 是顶点序列,满足对于任意 1≤i<k 1 leq i < k1i<k ,节点 Pi P_iPi​​ 和 Pi+1 P_{i+1}Pi+1​​ 之间都有边相连。
    简单路径:如果路径 P:P1,P2,,Pk 中,对于任意 1≤s≠t≤k 1 leq s eq t leq k1stk 都有 Ps≠Pt P_s eq P_tPs​​Pt​​ ,那么称路径为简单路径。

    输入格式

    输入文件的第一行包含两个整数 N NN 和 M MM ,分别代表图的顶点数和边数。
    接下来 M MM 行,每行包含四个整数 u uu、v vv、a aa、b bb 代表一条顶点 u uu 和 v vv 之间、权值为 2a⋅3b 2^a cdot 3^b2a​​3b​​ 的边。
    接下来一行包含一个整数 q qq ,代表询问数。
    接下来 q qq 行,每行包含四个整数 u uu 、v vv 、a aa 和 b bb,代表一次询问。
    询问内容请参见问题描述。

    输出格式

    对于每次询问,如果存在满足条件的路径,则输出一行 Yes,否则输出一行 No

    (注意:第一个字母大写,其余字母小写) 。

    样例

    样例输入

    4 5 
    1 2 1 3 
    1 3 1 2 
    1 4 2 1 
    2 4 3 2 
    3 4 2 2 
    5 
    1 4 3 3 
    4 2 2 3 
    1 3 2 2 
    2 3 2 2 
    1 3 4 4

    样例输出

    Yes 
    Yes 
    Yes 
    No 
    No

    数据范围与提示

    对于所有的数据,1≤n,q≤50000, 1≤m≤100000, 0≤a,b≤1091 leq n,q leq 50000, 1 leq m leq 100000, 0 leq a,b leq 10^91n,q50000, 1m100000, 0a,b109​​。

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #define maxn 50010
    using namespace std;
    int fa[maxn];
    int n,m;
    struct node{
        int u,v,a,b;
        bool operator < (const node &w) const {
            return a<w.a;
        }
    }E[100010];
    int find(int x){
        if(x==fa[x])return fa[x];
        return fa[x]=find(fa[x]);
    }
    int main(){
        scanf("%d%d",&n,&m);
        int x,y,a,b;
        for(int i=1;i<=m;i++)
            scanf("%d%d%d%d",&E[i].u,&E[i].v,&E[i].a,&E[i].b);
        int q;scanf("%d",&q);
        sort(E+1,E+m+1);
        for(int Case=1;Case<=q;Case++){
            for(int i=1;i<=n;i++)fa[i]=i;
            scanf("%d%d%d%d",&x,&y,&a,&b);
            if(x==y&&a==0&&b==0){puts("No");continue;}
            for(int i=1;i<=m;i++){
                if(E[i].a>a)break;
                if(E[i].b>b)continue;
                int f1=find(E[i].u),f2=find(E[i].v);
                if(f1!=f2)fa[f1]=f2;
            }
            if(find(x)!=find(y)){puts("No");continue;}
            int mxa=0,mxb=0;
            for(int i=1;i<=m;i++){
                if(E[i].a>a)break;
                if(E[i].b>b)continue;
                if(find(x)==find(E[i].v)&&find(x)==find(E[i].u)){
                    mxa=max(mxa,E[i].a);
                    mxb=max(mxb,E[i].b);
                }
            }
            if(mxa==a&&mxb==b)puts("Yes");
            else puts("No");
        }
        return 0;
    }
    20分 暴力
    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<cmath>
    #define maxn 100010
    using namespace std;
    int n,m,block,Q,top,opcnt;
    int fa[maxn],mxa[maxn],mxb[maxn],ans[maxn],sz[maxn];
    struct data{
        int x,y,a,b,id;
        void init(int i){
            id=i;
            scanf("%d%d%d%d",&x,&y,&a,&b);
        }
        bool operator < (const data &w)const{
            if(a==w.a)return b<w.b;
            return a<w.a;
        }
    }e[maxn],q[maxn],st[maxn];
    struct oper{int x,y,fa,mxa,mxb,sz;}op[maxn];
    bool cmp(data x,data y){
        if(x.b==y.b)return x.a<y.a;
        return x.b<y.b;
    }
    int find(int x){
        if(x==fa[x])return fa[x];
        return find(fa[x]);
    }
    void goback() {
        for (int i=opcnt; i; i--) {
            int x=op[i].x,y=op[i].y;
            fa[x]=op[i].fa;
            mxa[y]=op[i].mxa;
            mxb[y]=op[i].mxb;
            sz[y]=op[i].sz;
        }
        opcnt=0;
    }
    void merge(int x,int y,int a,int b) {
        x=find(x),y=find(y);
        if(sz[x]>sz[y])swap(x,y);
        op[++opcnt]=(oper){x,y,fa[x],mxa[y],mxb[y],sz[y]};
        if(x==y){
            mxa[y]=max(mxa[y],a),mxb[y]=max(mxb[y],b);
            return;
        }
        fa[x]=y,sz[y]+=sz[x];
        mxa[y]=max(mxa[x],max(mxa[y],a));
        mxb[y]=max(mxb[x],max(mxb[y],b));
    }
    int main(){
        scanf("%d%d",&n,&m);
        block=(int)sqrt(m);
        for(int i=1;i<=m;i++)e[i].init(i);
        sort(e+1,e+m+1);
        scanf("%d",&Q);
        for(int i=1;i<=Q;i++)q[i].init(i);
        sort(q+1,q+Q+1,cmp);
        for(int i=1;i<=m;i+=block){
            top=0;
            for(int j=1;j<=Q;j++)
                if(q[j].a>=e[i].a && (i+block>m || q[j].a<e[i+block].a))
                st[++top]=q[j];
            sort(e+1,e+i+1,cmp);
            for(int j=1;j<=n;j++)fa[j]=j,mxa[j]=mxb[j]=-1,sz[j]=1;
            for(int j=1,k=1;j<=top;j++){
                while(k<i&&e[k].b<=st[j].b){
                    merge(e[k].x,e[k].y,e[k].a,e[k].b);
                    k++;
                }
                opcnt=0;
                for(int l=i;l<i+block && l<=m;l++)
                    if(e[l].a<=st[j].a && e[l].b<=st[j].b)
                    merge(e[l].x,e[l].y,e[l].a,e[l].b);
                int x=find(st[j].x),y=find(st[j].y);
                if(x==y && mxa[x]==st[j].a && mxb[x]==st[j].b)ans[st[j].id]=1;
                else ans[st[j].id]=0;
                goback();
            }
        }
        for(int i=1;i<=Q;i++){
            if(ans[i])puts("Yes");
            else puts("No");
        }
        return 0;
    }
    100分 并查集启发式合并
  • 相关阅读:
    ASP.NET Core 返回 Json DateTime 格式
    IdentityServer4 SigningCredential(RSA 证书加密)
    IdentityServer4 指定角色授权(Authorize(Roles="admin"))
    ASP.NET Core 指定环境发布(hosting environment)
    ASP.NET Core 使用 Redis 客户端
    IdentityServer4 实现 OAuth 2.0(密码模式
    IdentityServer4 登录成功后,跳转到原来页面
    IdentityServer4 退出登录后,跳转到原来页面
    C#面向插件级别的软件开发
    使用XML序列化实现系统配置
  • 原文地址:https://www.cnblogs.com/thmyl/p/8990532.html
Copyright © 2011-2022 走看看