洛谷P3247 [HNOI2016]最小公倍數

題目描述

給定一張N個頂點M條邊的無向圖(頂點編號爲1,2,...,n),每條邊上帶有權值。所有權值都可以分解成2^a*3^b2a3b 的形式。

現在有q個詢問,每次詢問給定四個參數u、v、a和b,請你求出是否存在一條頂點u到v之間的路徑,使得路徑依次經過的邊上的權值的最小公倍數爲2^a*3^b2a3b 。

注意:路徑可以不是簡單路徑。下面是一些可能有用的定義:最小公倍數:K個數a1,a2,...,ak的最小公倍數是能被每個ai整除的最小正整數。

路徑:路徑P:P1,P2,...,Pk是頂點序列,滿足對於任意1<=i<k,節點Pi和Pi+1之間都有邊相連。簡單路徑:如果路徑P:P1,P2,...,Pk中,對於任意1\le s\ne t\le k1stk 都有Ps\ne PtPsPt ,那麼稱路徑爲簡單路徑。

輸入輸出格式

輸入格式:

輸入文件的第一行包含兩個整數N和M,分別代表圖的頂點數和邊數。接下來M行,每行包含四個整數u、v、a、b代表一條頂點u和v之間、權值爲2^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








分塊+可回溯並查集

真tm噁心。。。

附代碼:

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cmath>
#define MAXN 50010
using namespace std;
int n,m,q,l,sum;
int fa[MAXN],size[MAXN],maxa[MAXN],maxb[MAXN];
bool ans[MAXN];
struct node{
    int u,v,a,b,id;
}a[MAXN<<1],b[MAXN],c[MAXN];
struct node2{
    int u,v,fa,size,maxa,maxb;
}h[MAXN];
inline int read(){
	int date=0,w=1;char c=0;
	while(c<'0'||c>'9'){if(c=='-')w=-1;c=getchar();}
	while(c>='0'&&c<='9'){date=date*10+c-'0';c=getchar();}
	return date*w;
}
bool cmpa(const node &x,const node &y){
    if(x.a==y.a)return x.b<y.b;
    return x.a<y.a;
}
bool cmpb(const node &x,const node &y){
    if(x.b==y.b)return x.a<y.a;
    return x.b<y.b;
}
int find(int x){return fa[x]==x?x:find(fa[x]);}
void uniun(int u,int v,int a,int b){
    u=find(u);v=find(v);
    if(size[u]>size[v])swap(u,v);
    sum++;
    h[sum].u=u;h[sum].v=v;h[sum].maxa=maxa[v];h[sum].maxb=maxb[v];
    h[sum].fa=fa[u];h[sum].size=size[v];
    if(u==v){
        maxa[u]=max(maxa[u],a);
        maxb[u]=max(maxb[u],b);
        return;
    }
    fa[u]=v;
    size[v]+=size[u];
    maxa[v]=max(maxa[v],max(maxa[u],a));
    maxb[v]=max(maxb[v],max(maxb[u],b));
}
void back(){
    while(sum){
        fa[h[sum].u]=h[sum].fa;
        size[h[sum].v]=h[sum].size;
        maxa[h[sum].v]=h[sum].maxa;
        maxb[h[sum].v]=h[sum].maxb;
        sum--;
    }
}
void work(){
    for(int i=1;i<=m;i+=l){
        int top=0;
        for(int j=1;j<=q;j++)if(b[j].a>=a[i].a&&(i+l>m||b[j].a<a[i+l].a))c[++top]=b[j];
        sort(a+1,a+i,cmpb);
        for(int j=1;j<=n;j++){
            fa[j]=j;
            size[j]=1;
            maxa[j]=maxb[j]=-1;
        }
        for(int j=1,k=1;j<=top;j++){
            for(;k<i&&a[k].b<=c[j].b;k++)uniun(a[k].u,a[k].v,a[k].a,a[k].b);
            sum=0;
            for(int p=i;p<i+l&&p<=m;p++)
			if(a[p].a<=c[j].a&&a[p].b<=c[j].b)uniun(a[p].u,a[p].v,a[p].a,a[p].b);
            int x=find(c[j].u),y=find(c[j].v);
            ans[c[j].id]=(x==y&&maxa[x]==c[j].a&&maxb[x]==c[j].b);
            back();
        }
    }
    for(int i=1;i<=q;i++){
        if(ans[i])printf("Yes\n");
        else printf("No\n");
    }
}
void init(){
    n=read();m=read();
    for(int i=1;i<=m;i++){
        a[i].u=read();a[i].v=read();a[i].a=read();a[i].b=read();
        a[i].id=i;
    }
    q=read();
    for(int i=1;i<=q;i++){
        b[i].u=read();b[i].v=read();b[i].a=read();b[i].b=read();
        b[i].id=i;
    }
    sort(a+1,a+m+1,cmpa);
    sort(b+1,b+q+1,cmpb);
    l=sqrt(m);
}
int main(){
    init();
    work();
	return 0;
}


發佈了291 篇原創文章 · 獲贊 24 · 訪問量 5萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章