給你一棵樹,路徑有長度,多次詢問,每次給出 k,問你是否存在路徑長度為 k 的點對。
這道題我們用分治的方法。
那我們假設要解決乙個樹,那我們先選重心作為根節點(為了減少高度節省時間)。
然後就分成兩種討論,一種是路徑都在同乙個子樹中,那這個我們就可以把問題轉換為解決這個子樹。
另一種就是在兩個不同的子樹中(或者乙個是根節點)。那我們考慮直接搜出點到根節點的距離,然後任意兩個相加都是一種可行的 k
kk。(因為都是在不同子樹,或者是乙個是根節點的話距離就是另乙個到根節點的距離,所以是可以直接相加的)
首先,它可能是根節點,那它到根節點的距離就是 0
00,那乙個的距離為 0
00 就是存在的。
然後你考慮枚舉子樹,然後求出每個點到根節點的距離。然後我們這樣弄:我們列舉每個點和你給出的詢問(也就是離線弄)的 y
yy,那首先,這個點到根節點的距離 x
xx 一定是要小於等於 y
yy 的,然後如果要使得這個詢問的結果是有,那距離為 y−x
y-xy−
x 的點是一定要存在的,因為這樣就可以通過這兩個,得出 y
yy 的距離。
那你為了不會找到的點跟它是同乙個子樹中的,你就可以進行完上面的操作,才把你這個子樹的距離都標記為存在。
然後你每次不同的根統計那個存在的距離都是不同的,那你就要把之前的清空。
但是不能用 memset,因為陣列太大會超時。
但其實它真正有值的不多,那我們可以每次標記的時候把標記的點用乙個佇列記錄下來(棧也行,反正就是拿個陣列記錄值為 1
11 的位置),然後你要清空的時候就列舉這些值為 1
11 的地方,把它們賦值為 0
00 即可。
然後加個快讀什麼的就可以了。
#include
#include
#include
#include
#include
using
namespace std;
struct node e[
200001];
struct tree t[
100001];
int n, m, x, y, z, le[
100001
], kk;
bool in[
100001
], answer[
101]
;int ans[
10000001
], rem[
101]
, que[
10000001];
int d[
100001
], dis[
100001
], root;
int k, fa[
100001
], s, maxn[
100001];
intread()
while
(c >=
'0'&& c <=
'9')
return re;
}bool
cmp(
int x,
int y)
void
add(
int x,
int y,
int z)
; le[x]
= kk;
}void
find_root
(int now,
int father)
maxn[now]
=max
(maxn[now]
, s - t[now]
.s);
if(maxn[now]
< maxn[root])}
void
get_dis
(int now,
int father)
}void
count_
(int now)
}while
(que[0]
)}void
dfs(
int now)
}int
main()
for(
int i =
1; i <= m; i++)
s = n;
maxn[0]
= n;
root =0;
find_root(1
,0);
dfs(root)
;for
(int i =
1; i <= m; i++
)return0;
}
luogu P3806 模板 點分治1
題目描述 給定一棵有n個點的樹 詢問樹上距離為k的點對是否存在。多次詢問 可離線 我們先隨意指定乙個虛擬根root,將這棵樹轉化成無根樹 樹上的路徑可以分為兩類,1.經過根節點u的路徑 2.完全在u子樹裡 不經過u 的 對於1,用dis表示當前結點到根節點root的路徑長度,則root的子樹中兩個節...
Luogu P3806 模板 點分治1
給定一棵有 n nn 個點,邊權的樹,回答 m mm 個詢問,每次詢問樹上距離為 k kk 的點對是否存在。資料範圍n 1 04,m 100,邊權 10000,k 107 n leqslant 10 4,m leqslant 100,texttt leqslant 10000,k leqslant ...
luogu P3806 模板 點分治1
給你一棵樹,路徑有長度,多次詢問,每次給出 k,問你是否存在路徑長度為 k 的點對。這道題我們用分治的方法。那我們假設要解決乙個樹,那我們先選重心作為根節點 為了減少高度節省時間 然後就分成兩種討論,一種是路徑都在同乙個子樹中,那這個我們就可以把問題轉換為解決這個子樹。另一種就是在兩個不同的子樹中 ...