zoukankan      html  css  js  c++  java
  • [BZOJ4537][Hnoi2016]最小公倍数 奇怪的分块+可撤销并查集

    4537: [Hnoi2016]最小公倍数

    Time Limit: 40 Sec  Memory Limit: 512 MB
    Submit: 1474  Solved: 521
    [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

    考虑暴力做法,对于每一个询问,暴力加入满足询问的边,然后维护联通性和maxpmaxqmaxp,maxq,如果满足条件则YesYes。 
    两个条件的限制似乎很难用别的数据结构优化掉,那么考虑分块,先以pp为第一关键字,qq为第二关键字排序,每$m^{0.5}$分成一块。然后把每一个询问归类到相应的块中,使得这个询问的$p$大于等于块的$p$最小值小于等于最大值。 
    依次扫每个块,把每个块的询问取出来。设当前的块号是$i$,那么我们把$1$到$i-1$的块里面的所有的边按$b$排序,

    再把这个块内的询问按$q$排序。然后扫$1$到$i-1$的符合当前询问的边,加入并查集。对于i块内的边,只能暴力扫然后加入并查集了,注意处理完这个询问后,要撤销掉在该块内加入的边。

    所以此题的并查集不能路径压缩,要用启发式合并或按秩合并,两者都是$logn$的,总的时间复杂度时$O(n^{1.5}logn)$。

    将代码中的启发式换成按秩合并可AC否则TLE

     1 #include<iostream>
     2 #include<cstring>
     3 #include<cstdlib>
     4 #include<cstdio>
     5 #include<cmath>
     6 #include<algorithm>
     7 #define ll long long
     8 #define maxn 140105
     9 using namespace std;
    10 int read() {
    11     int x=0,f=1;char ch=getchar();
    12     for(;!isdigit(ch);ch=getchar()) if(ch=='-') f=-1;
    13     for(;isdigit(ch);ch=getchar()) x=x*10+ch-'0';
    14     return x*f;
    15 }
    16 int n,m,k;
    17 struct data {
    18     int a,b,p,q,id,f;
    19     bool operator <(const data tmp) const{
    20         return p==tmp.p?q<tmp.q:p<tmp.p;
    21     }
    22 }e[maxn],ask[maxn],tmp[maxn],sta[maxn];
    23 int fa[maxn],sz,ma[maxn],mb[maxn],size[maxn];
    24 int ans[maxn];
    25 int find(int x) {return fa[x]==x?fa[x]:find(fa[x]);}
    26 int cnt=0;
    27 void merge(int x,int y,int a,int b) {
    28     x=find(x),y=find(y);
    29     if(size[x]>size[y]) swap(x,y);
    30     sta[++cnt].a=x;sta[cnt].b=y;sta[cnt].p=ma[y];sta[cnt].q=mb[y];sta[cnt].f=fa[x];sta[cnt].id=size[y];
    31     if(x==y) {
    32         ma[x]=max(ma[x],a);
    33         mb[x]=max(mb[x],b);
    34     }
    35     else {
    36         fa[x]=y;
    37         size[y]+=size[x];
    38         ma[y]=max(ma[y],a);
    39         mb[y]=max(mb[y],b);
    40         ma[y]=max(ma[x],ma[y]);
    41         mb[y]=max(mb[x],mb[y]);
    42     }
    43 }
    44 bool cmp(data a,data b) {return a.q==b.q?a.p<b.p:a.q<b.q;}
    45 int main() {
    46  
    47     n=read(),m=read();
    48     for(int i=1;i<=m;i++) {
    49         e[i].a=read();e[i].b=read();e[i].p=read();e[i].q=read();
    50     }
    51     sort(e+1,e+m+1);
    52     sz=sqrt(m);
    53     k=read();
    54     for(int i=1;i<=k;i++) {
    55         ask[i].a=read(),ask[i].b=read(),ask[i].p=read(),ask[i].q=read();ask[i].id=i;
    56     }
    57     sort(ask+1,ask+k+1,cmp);
    58     for(int i=1;i<=m;i+=sz) {
    59         int top=0;
    60         for(int j=1;j<=k;j++) if(ask[j].p>=e[i].p&&(i+sz>m||ask[j].p<e[i+sz].p)) tmp[++top]=ask[j];
    61         sort(e+1,e+i,cmp);
    62         for(int j=1;j<=n;j++) fa[j]=j,size[j]=1,ma[j]=mb[j]=-2147483647;
    63         int w=1;
    64         for(int j=1;j<=top;j++) {
    65             for(;w<i;w++) {
    66                 if(e[w].q>tmp[j].q) break;
    67                 merge(e[w].a,e[w].b,e[w].p,e[w].q);
    68             }
    69             cnt=0;
    70             for(int t=i;t<i+sz;t++) {
    71                 if(e[t].p<=tmp[j].p&&e[t].q<=tmp[j].q) merge(e[t].a,e[t].b,e[t].p,e[t].q);
    72             }
    73             int t1=find(tmp[j].a),t2=find(tmp[j].b);
    74             if(t1==t2&&ma[t1]==tmp[j].p&&mb[t1]==tmp[j].q) ans[tmp[j].id]=1;
    75             while(cnt) {
    76                 fa[sta[cnt].a]=sta[cnt].f;
    77                 ma[sta[cnt].b]=sta[cnt].p;
    78                 mb[sta[cnt].b]=sta[cnt].q;
    79                 size[sta[cnt].b]=sta[cnt].id;
    80                 cnt--;
    81             }
    82         }
    83     }
    84     for(int i=1;i<=k;i++) if(ans[i]) puts("Yes");else puts("No");
    85      
    86 }
    View Code
    O(∩_∩)O~ (*^__^*) 嘻嘻…… O(∩_∩)O哈哈~
  • 相关阅读:
    Arduino mega 2560驱动安装失败(没有建立对验证码(TM)签名的目录的发布者信任)的解决方法
    Submile text3 安装使用技巧
    window.onload
    JS简单示例
    python类和对象的底层实现
    python类中方法加单下划线、双下划线、前后双下滑线的区别
    linux下json工具jq
    Django使用自定义的authentication登录认证
    django admin
    linux网卡桥接问题与docker网卡桥接问题
  • 原文地址:https://www.cnblogs.com/wls001/p/8435071.html
Copyright © 2011-2022 走看看