bzoj 4537 HNOI2016 最小公倍數

2022-09-07 06:42:09 字數 3168 閱讀 2794

給定一張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<=ii和pi+1之間都有邊相連。簡單路徑:如果路徑p:p1,p2,…,pk中,對於任意1

<=s≠t<=k都有ps≠pt,那麼稱路徑為簡單路徑。

輸入檔案的第一行包含兩個整數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

對於每次詢問,如果存在滿足條件的路徑,則輸出一行yes,否則輸出一行 no(注意:第乙個字母大寫,其餘

字母小寫) 。

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

yes

yes

yes

no no

這題就算數學只有幼兒園水平了應該也知道要求什麼吧。。。

就是給定乙個圖,每條邊有兩個權值:a和b,有多組詢問,讓你判斷是否在兩點間存在一條路徑使路徑上a的最大值為a,b的最大值為b;

首先考慮暴力的做法:對於每組詢問我們只加入滿足a限制的邊,再判斷兩點是否連通以及判斷最大值是否滿足。

這個東西的維護可以用乙個叫帶權並查集的乙個東西,聽起來很高階其實就是在並查集合並時加了乙個陣列而已

附上帶權並查集**:

1

void merge(int x,int y,int a,intb)2

6 fa[x]=y;size[y]+=size[x];

7 maxa[y]=max(maxa[y],max(a,maxa[x]));

8 maxb[y]=max(maxb[y],max(b,maxb[x]));

9 }

怎麼暴力怎麼來。。。

考慮到這種涉及兩個權值的問題一般都要限制住乙個條件

因為這種做法的缺陷在於它每次都要對所有的邊進行處理,即必須對每個詢問都重新構圖,暴力判斷。。。

那麼我們考慮離線做法吧。。。

這題的思想極其巧妙,把邊按照a的權值分塊,詢問按照b的權值排序!!!

-----真的不知道怎麼想出來的。

直接說做法吧。。。

1.對於每個塊,把滿足這個塊的a的條件的詢問找出來。。。

2.我們對於這些滿足的詢問分兩種情況來考慮目前對該詢問的貢獻:這個塊之前的邊(整塊),這個塊目前的邊(非整塊);

3.對於第一種情況,那麼對於這些詢問來說,這個塊以前的塊中的邊是一定a的條件的!!!(因為是按照a從小到大排序了的)

4.也就是說這些這些邊只要滿足b的條件即可,那麼可以把這些邊按bsort。

5.再把這些邊只需按照滿足b的條件依次加入即可。。。注意這些加入的邊對於以後的詢問也是會用到的,因為詢問的邊的b是遞增的,所以每次不需重構圖。

6.對於第二種情況,這些邊的a和b都需要滿足條件。。

7.並且由於滿足這個塊的詢問的a並不一定是公升序的,所以可能對於滿足的兩個詢問i,j;

biaj;這樣就會有乙個尷尬的問題,一條邊的ax可能滿足aj回溯功能,即把剛剛加入  的邊刪掉;利用棧把每次加邊之前的狀態全部記錄下來即可,加完後在回溯。

8.第一遍wa了,有點醉。。。

1

for(int i=1;i<=q;i++)

2

具體實現如下:

1 #include2 #include3 #include4 #include5 #include6

using

namespace

std;

7const

int n=1000050;8

intgi()916

struct

ac17

edge[n],query[n];

20int

n,m,q,block,pos[n],l[n],r[n],cnt,canuse[n],tt;

21int

fa[n],maxa[n],maxb[n],size[n],ans[n];

22struct

ac23

add[n];

26bool cmpa(const ac &a,const ac &b)

2731

bool cmpb(const ac &a,const ac &b)

3236

int find(int x)

37void merge(int x,int y,int a,int

b)38;42

if(x==y)

43 fa[x]=y;size[y]+=size[x];

44 maxa[y]=max(maxa[y],max(a,maxa[x]));

45 maxb[y]=max(maxb[y],max(b,maxb[x]));46}

47void

del()

4854 tt=0;55

}56intmain()

5783

int x=find(query[canuse[j]].x),y=find(query[canuse[j]].y);

84if(x==y&&maxa[x]==query[canuse[j]].a&&maxb[y]==query[canuse[j]].b) ans[query[canuse[j]].id]=1;85

else ans[query[canuse[j]].id]=0;86

del();87}

88}89for(int i=1;i<=q;i++)

9094 }

bzoj4537 HNOI2016 最小公倍數

time limit 40 sec memory limit 512 mb submit 563 solved 236 submit status discuss 給定一張n個頂點m條邊的無向圖 頂點編號為1,2,n 每條邊上帶有權值。所有權值都可以分解成2 a 3 b 的形式。現在有q個詢問,每次...

BZOJ4537 HNOI2016 最小公倍數

那個,事情是這樣的,從前有乙隻蒟蒻 對,就是我 然後有一天他心血來潮想創個部落格。可是沒過多久,他的熱情就過去了,甚至連一篇博文都沒有寫。然後,不知道怎麼了,他的部落格就被機房裡的dalao翻出來了,還被嘲諷了一番。於是他決定補救一下他的部落格。嗯,就這樣。這道題大概是這樣的。給定一張n個點m條邊的...

BZOJ4537 Hnoi2016 最小公倍數

給定一張n個頂點m條邊的無向圖 頂點編號為1,2,n 每條邊上帶有權值。所有權值都可以分解成2 a 3 b 的形式。現在有q個詢問,每次詢問給定四個引數u v a和b,請你求出是否存在一條頂點u到v之間的路徑,使得 路徑依次經過的邊上的權值的最小公倍數為2 a 3 b。注意 路徑可以不是簡單路徑。下...