zoukankan      html  css  js  c++  java
  • [BZOJ4537][HNOI2016]最小公倍数(分块+并查集)

    4537: [Hnoi2016]最小公倍数

    Time Limit: 40 Sec  Memory Limit: 512 MB
    Submit: 1687  Solved: 607
    [Submit][Status][Discuss]

    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

    HINT

    Source

    [Submit][Status][Discuss]

    首先如果只有一个参数a,可以直接将边和询问排序然后扫一遍即可。

    现在是二维偏序问题,我们就需要合理分块了。

    将边按a排序,询问按b排序,考虑分块,每次找到所有第一关键字在[L,R]中的询问,那么我们将第一关键字在[1,L)的边按第二关键字排序,就可以指针扫一遍统计答案了,对于块内的问题,直接暴力合并和撤销并查集操作即可。

     1 #include<cmath>
     2 #include<cstdio>
     3 #include<algorithm>
     4 #define rep(i,l,r) for (int i=l; i<=r; i++)
     5 using namespace std;
     6 
     7 const int N=100100;
     8 struct E{ int x,y,u,v,k; }a[N],b[N],c[N],h[N];
     9 void up(int &x,int y){ if (x<y) x=y; }
    10 
    11 bool ans[N];
    12 int n,m,cnt,tot,fa[N],sz[N],fu[N],fv[N];
    13 bool cmpu(const E &p,const E &q){ return p.u<q.u || (p.u==q.u && p.v<q.v); }
    14 bool cmpv(const E &p,const E &q){ return p.v<q.v || (p.v==q.v && p.u<q.u); }
    15 int getfa(int x){ return (x==fa[x]) ? x : getfa(fa[x]); }
    16 
    17 void merge(int x,int y,int u,int v){
    18     x=getfa(x); y=getfa(y); if (sz[x]>sz[y]) swap(x,y);
    19     h[++tot]=(E){x,y,fu[y],fv[y],sz[y]};
    20     if (x!=y) fa[x]=y,sz[y]+=sz[x],up(fu[y],fu[x]),up(fv[y],fv[x]);
    21     up(fu[y],u); up(fv[y],v);
    22 }
    23 
    24 int main(){
    25     freopen("bzoj4537.in","r",stdin);
    26     freopen("bzoj4537.out","w",stdout);
    27     scanf("%d%d",&n,&m);
    28     rep(i,1,m) scanf("%d%d%d%d",&a[i].x,&a[i].y,&a[i].u,&a[i].v);
    29     sort(a+1,a+m+1,cmpu); scanf("%d",&cnt);
    30     rep(i,1,cnt) scanf("%d%d%d%d",&b[i].x,&b[i].y,&b[i].u,&b[i].v),b[i].k=i;
    31     sort(b+1,b+cnt+1,cmpv);
    32     int bl=sqrt(m);
    33     for (int i=1; i<=m; i+=bl){
    34         rep(j,1,n) fa[j]=j,fu[j]=fv[j]=-1,sz[j]=1;
    35         int len=0;
    36         rep(j,1,cnt) if (b[j].u>=a[i].u && (i+bl>m || b[j].u<a[i+bl].u)) c[++len]=b[j];
    37         if (!len) continue;
    38         if (i>1) sort(a+1,a+i,cmpv);
    39         for (int j=1,k=1; j<=len; j++){
    40             for (; k<i && a[k].v<=c[j].v; k++) merge(a[k].x,a[k].y,a[k].u,a[k].v);
    41             tot=0;
    42             for (int l=i; l<i+bl && l<=m; l++)
    43                 if (a[l].u<=c[j].u && a[l].v<=c[j].v) merge(a[l].x,a[l].y,a[l].u,a[l].v);
    44             int p=getfa(c[j].x),q=getfa(c[j].y);
    45             ans[c[j].k]=(p==q && fu[p]==c[j].u && fv[p]==c[j].v);
    46             for (; tot; tot--) p=h[tot].x,q=h[tot].y,fa[p]=p,fu[q]=h[tot].u,fv[q]=h[tot].v,sz[q]=h[tot].k;
    47         }
    48     }
    49     rep(i,1,cnt) puts(ans[i]?"Yes":"No");
    50     return 0;
    51 }
  • 相关阅读:
    NS2 nam中节点及数据流颜色设置
    JSF简单介绍
    深入浅出谈开窗函数(一)
    BZOJ2440(全然平方数)二分+莫比乌斯容斥
    怎样在SharePoint管理中心检查数据库架构版本号、修补级别和修补程序的常规监控
    Java实现BASE64编解码
    博弈 个人 见解
    【剑指offer】第一个仅仅出现一次的字符
    cocos2d基础篇笔记四
    SSL连接建立过程分析(1)
  • 原文地址:https://www.cnblogs.com/HocRiser/p/8727490.html
Copyright © 2011-2022 走看看