zoukankan      html  css  js  c++  java
  • 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(注意:第一个字母大写,其余
    字母小写) 。

    存在合法路径等价于只保留a,b均不超过询问值的边,两点联通且a,b的最值分别能取到
    对分块实现的莫队算法稍作修改就可以处理这个问题
    将边按a分块,保证a相同的边分在同一块,且块大小尽可能在O(n/sqrt(m))
    询问也分到对应的块中,对每个块,按b升序处理,左边的块内的边可以直接在并查集上修改,当前块内暴力修改和撤销
    但若块大小因为a相同分到同一块的限制而较大则不能保证复杂度,对这种特殊情况,由于特殊性可以把当前块和左边的块内的边一起处理而不用撤销
    总复杂度O(nsqrt(m)logn+mlongm)
    #include<cstdio>
    #include<cmath>
    #include<algorithm>
    #include<cstring>
    #define G *++ptr
    const int N=50007;
    char buf[10000007],*ptr=buf-1;
    int _(){
        int x=0,c=G;
        while(c<48)c=G;
        while(c>47)x=x*10+c-48,c=G;
        return x;
    }
    int n,m,q;
    bool as[N];
    
    int f[N],xm[N],ym[N],B,bs[N],bp=0,*o1[N],o2[N],op=0;
    void undo(){
        while(op)--op,*o1[op]=o2[op];
    }
    inline void set(int*x,int y){
        o1[op]=x;
        o2[op++]=*x;
        *x=y;
    }
    void init(){
        memset(f,-1,sizeof(int)*(n+2));
        memset(xm,-1,sizeof(int)*(n+2));
        memset(ym,-1,sizeof(int)*(n+2));
    }
    inline int gf(int x){
        while(f[x]>0)x=f[x];
        return x;
    }
    struct Q{
        int u,v,x,y,id;
        void init(int i){
            u=_();v=_();x=_();y=_();
            id=i;
        }
        void cal(){
            int a=gf(u),b=gf(v);
            if(a==b&&xm[a]==x&&ym[b]==y)as[id]=1;
        }
    }qs[N];
    bool qcmpx(const Q&a,const Q&b){return a.x<b.x;}
    bool qcmpy(const Q&a,const Q&b){return a.y<b.y;}
    int max(int a,int b){return a>b?a:b;}
    struct edge{
        int u,v,x,y;
        void init(){
            u=_();v=_();x=_();y=_();
        }
        void cal(){
            int a=gf(u),b=gf(v);
            if(a!=b){
                if(f[a]<f[b])std::swap(a,b);
                if(f[a]==f[b])--f[b];
                f[a]=b;
            }
            int xx=max(xm[a],x),yy=max(ym[a],y);
            if(xx>xm[b])xm[b]=xx;
            if(yy>ym[b])ym[b]=yy;
        }
        void cal_(){
            int a=gf(u),b=gf(v);
            if(a!=b){
                if(f[a]<f[b])std::swap(a,b);
                if(f[a]==f[b])set(f+b,f[b]-1);
                set(f+a,b);
            }
            int xx=max(xm[a],x),yy=max(ym[a],y);
            if(xx>xm[b])set(xm+b,xx);
            if(yy>ym[b])set(ym+b,yy);
        }
    }e[N*2];
    bool ecmpx(const edge&a,const edge&b){return a.x<b.x;}
    bool ecmpy(const edge&a,const edge&b){return a.y<b.y;}
    void msort(edge*l,edge*m,edge*r){
        static edge ee[N*2];
        std::sort(m,r,ecmpy);
        if(l==m||m==r)return;
        edge*p1=l,*p2=m,*p3=ee;
        while(p1!=m&&p2!=r)*p3++=p1->y<p2->y?*p1++:*p2++;
        while(p1!=m)*p3++=*p1++;
        while(p2!=r)*p3++=*p2++;
        memcpy(l,ee,(p3-ee)*sizeof(edge));
    }
    int main(){
        fread(buf,1,sizeof(buf),stdin)[buf]=0;
        n=_();m=_();
        B=n/sqrt(m+1)*2+1;
        for(int i=0;i<m;++i)e[i].init();
        q=_();
        for(int i=0;i<q;++i)qs[i].init(i);
        std::sort(qs,qs+q,qcmpx);
        std::sort(e,e+m,ecmpx);
        for(int i=0,j=0;i<m;i=j){
            for(;j<m&&e[i].x==e[j].x;++j);
            if(j-bs[bp]>B)bs[++bp]=i;
        }
        e[bs[++bp]=m].x=0x3f3f3f3f;
        for(int b=0,l=0,r=0,S=0;b<bp;++b){
            int L=bs[b],R=bs[b+1];
            
            for(l=r;r<q&&qs[r].x<e[R].x;++r);
            std::sort(qs+l,qs+r,qcmpy);
            
            if(e[L].x==e[R-1].x){
                msort(e,e+S,e+R);S=R;
                init();
                for(int ep=0,p=l;p<r;++p){
                    Q&w=qs[p];
                    for(;ep<R&&e[ep].y<=w.y;++ep)e[ep].cal();
                    w.cal();
                }
            }else{
                msort(e,e+S,e+L);S=L;
                init();
                for(int ep=0,p=l;p<r;++p){
                    Q&w=qs[p];
                    for(;ep<L&&e[ep].y<=w.y;++ep)e[ep].cal();
                    for(int ep=L;ep<R;++ep)if(e[ep].x<=w.x&&e[ep].y<=w.y)e[ep].cal_();
                    w.cal();
                    undo();
                }
            }
        }
        for(int i=0;i<q;++i)puts(as[i]?"Yes":"No");
        return 0;
    }
     
  • 相关阅读:
    java、asp.net 通用分页码函数
    SQL
    go build 参数
    alertmanager报错Failed to get final advertise address: No private IP address found, and explicit IP not provided"
    go语言三个点的用法
    CDH6.2安装
    python之链表
    jenkins触发构建后一直重复构建
    ansible远程执行寻找不到环境变量问题
    Python3之harbor sdk api
  • 原文地址:https://www.cnblogs.com/ccz181078/p/6607323.html
Copyright © 2011-2022 走看看