• BZOJ4537: [Hnoi2016]最小公倍数


    Description

      给定一张N个顶点M条边的无向图(顶点编号为1,2,…,n),每条边上带有权值。所有权值都可以分解成2^a*3^b
    的形式。现在有q个询问,每次询问给定四个参数u、v、a和b,请你求出是否存在一条顶点u到v之间的路径,使得
    路径依次经过的边上的权值的最小公倍数为2^a*3^b。注意:路径可以不是简单路径。下面是一些可能有用的定义
    :最小公倍数:K个数a1,a2,…,ak的最小公倍数是能被每个ai整除的最小正整数。路径:路径P:P1,P2,…,Pk是顶
    点序列,满足对于任意1<=i<k,节点Pi和Pi+1之间都有边相连。简单路径:如果路径P:P1,P2,…,Pk中,对于任意1
    <=s≠t<=k都有Ps≠Pt,那么称路径为简单路径。

    Input

      输入文件的第一行包含两个整数N和M,分别代表图的顶点数和边数。接下来M行,每行包含四个整数u、v、a、
    b代表一条顶点u和v之间、权值为2^a*3^b的边。接下来一行包含一个整数q,代表询问数。接下来q行,每行包含四
    个整数u、v、a和b,代表一次询问。询问内容请参见问题描述。1<=n,q<=50000、1<=m<=100000、0<=a,b<=10^9

    Output

      对于每次询问,如果存在满足条件的路径,则输出一行Yes,否则输出一行 No(注意:第一个字母大写,其余
    字母小写) 。

    Sample Input

    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

    Sample Output

    Yes
    Yes
    Yes
    No
    No
     
    考虑这样一种暴力,对于每个询问(u,v,A,B),将a<=A和b<=B的边全部加入并查集中,最后判断u和v是否在同一连通分量中且连通分量包含的最大的a=A,最大的b=B即可。
    再考虑这样一种暴力,把询问和边离线按a排序,询问时在已经加入的边中按b值排序加入并查集中。
    那么我们把这两种暴力结合起来,按a值将询问和边分块,前面的边按第二种做法做,块内的边按第一种做法做就行了。
    因为并查集需要支持撤销,所以要用按秩合并,时间复杂度为O(Nsqrt(N)logn)
    #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;i=next[i])
    using namespace std;
    const int BufferSize=1<<16;
    char buffer[BufferSize],*head,*tail;
    inline char Getchar() {
        if(head==tail) {
            int l=fread(buffer,1,BufferSize,stdin);
            tail=(head=buffer)+l;
        }
        return *head++;
    }
    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=50010;
    const int maxm=100010;
    int n,m,q;
    struct Query {
        int u,v,a,b,tp;
        bool operator < (const Query& ths) const {return b<ths.b||(b==ths.b&&tp<ths.tp);}
    }E[maxm],Q[maxn],T[maxm*2];
    int pa[maxn],rk[maxn],mxa[maxn],mxb[maxn];
    int findset(int x) {return pa[x]==x?x:findset(pa[x]);}
    struct Data {int x,y,rk,mxa,mxb;}S[maxm];
    int top,ans[maxn];
    void merge(int u,int v,int a,int b) {
        int x=findset(u),y=findset(v);
        if(rk[x]<rk[y]) swap(x,y);
        S[++top]=(Data){x,y,rk[x],mxa[x],mxb[x]};
        pa[y]=x;mxa[x]=max(mxa[x],mxa[y]);mxb[x]=max(mxb[x],mxb[y]);
        mxa[x]=max(mxa[x],a);mxb[x]=max(mxb[x],b);
        if(rk[x]==rk[y]) rk[x]++;
    }
    void del() {
        int x=S[top].x,y=S[top].y;
        pa[y]=y;rk[x]=S[top].rk;mxa[x]=S[top].mxa;mxb[x]=S[top].mxb;
        top--;
    }
    bool cmp(Query a,Query b) {return a.a<b.a;}
    int main() {
        n=read();m=read();
        rep(i,1,m) E[i].tp=0,E[i].u=read(),E[i].v=read(),E[i].a=read(),E[i].b=read();
        q=read();rep(i,1,q) Q[i].tp=i,Q[i].u=read(),Q[i].v=read(),Q[i].a=read(),Q[i].b=read();
        int SIZE=sqrt(m*2),cnt=0;
        sort(E+1,E+m+1,cmp);
        sort(Q+1,Q+q+1,cmp);
        rep(i,1,m) {
            if((++cnt==SIZE)||i==m) {
                int N=0;
                rep(j,1,i-cnt) T[++N]=E[j];
                rep(j,1,q) if(Q[j].a>=E[i-cnt+1].a&&(i==m||Q[j].a<E[i+1].a)) T[++N]=Q[j];
                if(i-cnt!=N) {
                    rep(j,1,n) pa[j]=j,rk[j]=0,mxa[j]=mxb[j]=-1;
                    sort(T+1,T+N+1);top=0;
                    rep(j,1,N) {
                        if(T[j].tp) {
                            rep(k,i-cnt+1,i+1) {
                                if(E[k].a>T[j].a||k>i) {
                                    int pa1=findset(T[j].u),pa2=findset(T[j].v);
                                    if(pa1==pa2&&mxa[pa1]==T[j].a&&mxb[pa1]==T[j].b) ans[T[j].tp]=1;
                                    rep(z,i-cnt+1,k-1) if(E[z].b<=T[j].b) del();
                                    break;
                                }
                                if(E[k].b<=T[j].b) merge(E[k].u,E[k].v,E[k].a,E[k].b);
                            }
                        }
                        else merge(T[j].u,T[j].v,T[j].a,T[j].b);
                    }
                }
                cnt=0;
            }
        }
        rep(i,1,q) puts(ans[i]?"Yes":"No");
        return 0;
    }
    

      

  • 相关阅读:
    [PY3]——logging
    [PY3]——对iterator的处理(解析式、map、reduce、filter)
    php基础语法(文件加载和错误)
    php基础语法(控制语句、数组、函数)
    php基础语法(数据类型、运算符)
    php基础语法(变量)
    java基础语法
    ztree 获取根节点
    每天一个linux命令
    浅谈Web自适应
  • 原文地址:https://www.cnblogs.com/wzj-is-a-juruo/p/5450185.html
Copyright © 2020-2023  润新知