bzoj3251 樹上三角形

2022-04-30 08:21:09 字數 1696 閱讀 1222

傳送門

題目

給定一大小為n的有點權樹,每次詢問一對點(u,v),問是否能在u到v的簡單路徑上取三個點權,以這三個權值為邊

長構成乙個三角形。同時還支援單點修改。

input

第一行兩個整數n、q表示樹的點數和運算元

第二行n個整數表示n個點的點權

以下n-1行,每行2個整數a、b,表示a是b的父親(以1為根的情況下)

以下q行,每行3個整數t、a、b

若t=0,則詢問(a,b)

若t=1,則將點a的點權修改為b

n,q<=100000,點權範圍[1,2^31-1]

output

對每個詢問輸出一行表示答案,「y」表示有解,「n」表示無解。

sample input

5 51 2 3 4 5

1 22 3

3 41 5

0 1 3

0 4 5

1 1 4

0 2 5

0 2 3

sample outputny

yn分析

一道十分帶勁的腦洞題。設每乙個點的點權為di,如果要形成三角形,在點權排好序後至少應該有乙個i滿足di-2+di-1>di,那麼我們考慮所有都不可能的情況,這種情況的臨界情況即為對於所有的i都有di-2+di-1=di,這不由讓我們想到了斐波那契公式。所以如果路徑經過的點的個數多於d的範圍內按斐波那契公式排列的數的個數則一定可以組成三角形。而點權範圍是int,int內的斐波那契數大約有50個,所以如果兩點間的路徑的點數大於等於50個直接輸出y。然後我們考慮點數小於50的情況,因為這種情況下點數很少,所以我們只需暴力lca記錄路徑上的點權,然後排序判斷即可。

ps.我也不不知道為啥用1ll就掛了,以後還是不要用了把......

**

#include#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

using

namespace

std;

int fa[210000],d[210000],a[210000],dep[210000

];vector

v[210000

];void dfs(int

x)

return;}

intmain()

dep[

1]=1

; dfs(1);

for(i=1;i<=m;i++)

}while(x!=y)

}a[++cnt]=d[x];

if(cnt>=50)ok=1

;

if(!ok)

}if(!ok)printf("

n\n"

);

else printf("

y\n"

); }

}return0;

}

bzoj3251 樹上三角形

給定一大小為n的有點權樹,每次詢問一對點 u,v 問是否能在u到v的簡單路徑上取三個點權,以這三個權值為邊長構成乙個三角形。同時還支援單點修改。第一行兩個整數n q表示樹的點數和運算元 第二行n個整數表示n個點的點權 以下n 1行,每行2個整數a b,表示a是b的父親 以1為根的情況下 以下q行,每...

bzoj3251 樹上三角形

題意 有根樹,支援兩種操作,詢問從u v的簡單路徑上是否存在三個點權可以構成三角形,單點修改點權。暑假多校的時候就見過這個斐波那契性質。兩邊之和大於第三邊,顯然這是個很套路的東西,這個性質就是斐波那契性質,而斐波那契數列至多在五十項左右的時候炸int,故若簡單路徑長度大於50,那麼必然有解,否則暴力...

BZOJ 3251 樹上三角形

傳送門 看到這種奇怪的要求,考慮一下推結論 考慮把路徑上的點權拿出來排序,變成乙個數列,那麼顯然我們只要考慮相鄰連續的 3 個數 發現如果我們貪心構造乙個盡量無法構成三角形的數列,那麼最小的數列就是斐波那契數列 眾所周知斐波那契數列增長很快,第 50 項顯然遠大於題目給出的點權範圍,所以如果 u,v...