• [HNOI2016]最小公倍数


    题目描述

    给定一张N个顶点M条边的无向图(顶点编号为1,2,...,n),每条边上带有权值。所有权值都可以分解成2a∗3b2^a*3^b2a3b 的形式。

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

    注意:路径可以不是简单路径。下面是一些可能有用的定义:最小公倍数:K个数a1,a2,...,ak的最小公倍数是能被每个ai整除的最小正整数。

    路径:路径P:P1,P2,...,Pk是顶点序列,满足对于任意1<=i<k,节点Pi和Pi+1之间都有边相连。简单路径:如果路径P:P1,P2,...,Pk中,对于任意1≤s≠t≤k1le s e tle k1stk 都有Ps≠PtPs e PtPsPt ,那么称路径为简单路径。

    输入输出格式

    输入格式:

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

    输出格式:

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

    输入输出样例

    输入样例#1: 复制
    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
    输出样例#1: 复制
    Yes 
    Yes 
    Yes 
    No 
    No
    对于每个询问,我们可以把所有(a,b)小于等于的边加入并查集
    并查集维护联通块的最大a和最大b,分别为Maxa,Maxb
    如果最大(Maxa,Maxb)=(a,b)
    暴力显然不行
    现将边按a排序,分块
    将询问按b排序

    每一块加入a值在这一块的范围内的询问,即大于等于a[i]小于a[i+√m]
    前面的块里的边显然a值都符合需求,按b排序
    从前往后枚举加入的询问,将前面块里小于b的边加入
    因为满足当前询问的边,必定也满足下一个询问,所以不需要撤销
    然后枚举当前块里的边加入,处理完当前询问要撤销并查集的操作
    因为撤销操作需要储存状态并复原,只有根号个撤销操作,复杂度有保证
    不能用路径压缩
      1 #include<iostream>
      2 #include<cstdio>
      3 #include<cstring>
      4 #include<algorithm>
      5 #include<cmath>
      6 using namespace std;
      7 struct Node
      8 {
      9   int u,v,a,b,id;
     10 }e[100001],q[50001],pre[100001],p[50001];
     11 int set[50001],tot,Maxa[50001],Maxb[50001],n,m,lim,r,cnt,ans[50001],size[50001];
     12 int gi()
     13 {
     14   char ch=getchar();
     15   int x=0;
     16   while (ch<'0'||ch>'9') ch=getchar();
     17   while (ch>='0'&&ch<='9')
     18     {
     19       x=(x<<3)+(x<<1)+ch-'0';
     20       ch=getchar();
     21     }
     22   return x;
     23 }
     24 bool cmpa(Node x,Node y)
     25 {
     26   if (x.a==y.a) return x.b<y.b;
     27   return x.a<y.a;
     28 }
     29 bool cmpb(Node x,Node y)
     30 {
     31   if (x.b==y.b) return x.a<y.a;
     32   return x.b<y.b;
     33 }
     34 int find(int x)
     35 {
     36   if (set[x]==x) return x;
     37   if (set[x]!=x) return find(set[x]);
     38 }
     39 void merge(Node E)
     40 {
     41   int p=find(E.u),q=find(E.v);
     42   if (size[p]<size[q]) swap(p,q);
     43   ++tot;
     44   pre[tot].u=p,pre[tot].v=q,pre[tot].a=Maxa[p],pre[tot].b=Maxb[p];pre[tot].id=size[p];
     45   if (p!=q)
     46     {
     47       set[q]=p;
     48       size[p]+=size[q];
     49     }
     50   if (Maxa[p]<E.a)
     51     Maxa[p]=E.a;
     52   if (Maxa[p]<Maxa[q])
     53     Maxa[p]=Maxa[q];
     54   if (Maxb[p]<E.b)
     55     Maxb[p]=E.b;
     56   if (Maxb[p]<Maxb[q])
     57     Maxb[p]=Maxb[q];
     58 }
     59 void undo()
     60 {int i;
     61   Node E;
     62   for (;tot;tot--)
     63     {
     64       E=pre[tot];
     65       set[E.v]=E.v;
     66       Maxa[E.u]=E.a;
     67       Maxb[E.u]=E.b;
     68       size[E.u]=E.id;
     69     }
     70 }
     71 int main()
     72 {int i,j,k,l,ed,p1,p2;
     73   cin>>n>>m;
     74   lim=sqrt(m);
     75   for (i=1;i<=m;i++)
     76     {
     77       e[i].u=gi();e[i].v=gi();e[i].a=gi();e[i].b=gi();
     78       e[i].id=i;
     79     }
     80   cin>>r;
     81   for (i=1;i<=r;i++)
     82     {
     83       q[i].u=gi();q[i].v=gi();q[i].a=gi();q[i].b=gi();
     84       q[i].id=i;
     85     }
     86   sort(e+1,e+m+1,cmpa);
     87   sort(q+1,q+r+1,cmpb);
     88   for (i=1;i<=m;i+=lim)
     89     {
     90       cnt=0;tot=0;
     91       k=1;
     92       for (j=1;j<=r;j++)
     93     if (q[j].a>=e[i].a&&(i+lim>m||q[j].a<e[i+lim].a))
     94       p[++cnt]=q[j];
     95       if (cnt==0) continue;
     96       sort(e+1,e+i,cmpb);
     97       if (i+lim-1<=m) ed=i+lim-1;
     98       else ed=m;
     99       for (j=1;j<=n;j++)
    100     set[j]=j,Maxa[j]=-1,Maxb[j]=-1,size[j]=1;
    101       for (j=1;j<=cnt;j++)
    102     {
    103       for (;k<i;k++)
    104         if (p[j].b>=e[k].b) merge(e[k]);
    105         else break;
    106       tot=0;
    107       for (l=i;l<=ed;l++)
    108         if (p[j].b>=e[l].b&&p[j].a>=e[l].a)
    109           {
    110         merge(e[l]);
    111           }
    112         else if (e[l].a>p[j].a) break;
    113       p1=find(p[j].u),p2=find(p[j].v);
    114       if (p1==p2&&Maxa[p1]==p[j].a&&Maxb[p1]==p[j].b)
    115         ans[p[j].id]=1;
    116       undo();
    117     }
    118     }
    119   for (i=1;i<=r;i++)
    120     if (ans[i])
    121       puts("Yes");
    122     else puts("No");
    123 }
  • 相关阅读:
    2D ARPG开发之旅(1) 贴图(tilebased)地图的实现(上)贴图修改版
    Microsoft CRM 2011 出现“无法更改域登录名" 错误
    Microsoft CRM 2011 隐藏文件菜单中的”新建活动“菜单
    Microsoft CRM 2011 安装时出现“Could not find GUID for server, Global Catalog not found in forest xxx”的问题
    C#(面向对象)
    delegate(委托)
    ww
    SQL(存储过程,触发器,回滚)
    sss
    EXcel
  • 原文地址:https://www.cnblogs.com/Y-E-T-I/p/8516600.html
Copyright © 2020-2023  润新知