BZOJ1316 樹上的詢問 點分治

2021-08-29 02:21:43 字數 2199 閱讀 4856

一棵n個點的帶權有根樹,有p個詢問,每次詢問樹中是否存在一條長度為len的路徑,如果是,輸出yes否輸出no.

第一行兩個整數n, p分別表示點的個數和詢問的個數. 接下來n-1行每行三個數x, y, c,表示有一條樹邊x→y,長度為c. 接下來p行每行乙個數len,表示詢問樹中是否存在一條長度為len的路徑.

輸出有p行,yes或no.

6 4 

1 2 5

1 3 7

1 4 1

3 5 2

3 6 3

1 8

13 14

yes 

yes

no yes

30%的資料,n≤100.

100%的資料,n≤10000,p≤100,長度≤1000000.

利用點分治,首先把樹的重心找出來之後,然後以這一點為根,遞迴的解決,點分治處理的是經過根節點的路徑,所以在計算完當前節點之後要去重(兒子),每次把處理的所有深度排序,然後遍歷每乙個深度值,看一下存在k-x的有多少個累加這個值就是答案,利用二分實現。先把所有的查詢存下來,然後離線處理。

#include

using

namespace std;

#define mem(a, b) memset(a, b, sizeof(a))

const

int n =

1e4+10;

int first[n]

, tot, n, p;

int q[n]

, siz[n]

, f[n]

, d[n]

, deep[n]

, vis[n]

;int sum, root;

struct edge

e[n *2]

;void

add_edge

(int u,

int v,

int w)

void

init()

void

getroot

(int u,

int fa)

} f[u]

=max

(f[u]

, sum - siz[u]);

if(f[u]

< f[root]

) root = u;

}void

getdeep

(int u,

int fa)}}

intfindl

(int l,

int r,

int k)

else

if(deep[mid]

< k)

l = mid +1;

else

r = mid -1;

}return ans;

}int

findr

(int l,

int r,

int k)

else

if(deep[mid]

< k)

l = mid +1;

else

r = mid -1;

}return ans;

}int

cal(

int u,

int cost,

int k)

return t;

}int ans[

110]

;void

solve

(int u)}}

intmain()

for(

int i =

1; i <= p; i++

)scanf

("%d"

,&q[i]);

getroot(1

,0);

solve

(root)

;for

(int i =

1; i <= p; i++

)puts

(ans[i]

?"yes"

:"no");

return0;

}

BZOJ 1316 樹上的詢問 點分治

time limit 10 sec memory limit 162 mb submit 691 solved 187 submit status discuss 一棵n個點的帶權有根樹,有p個詢問,每次詢問樹中是否存在一條長度為len的路徑,如果是,輸出yes否輸出no.第一行兩個整數n,p分別表...

BZOJ1316 樹上的詢問 點分治

time limit 10 sec memory limit 162 mb submit 1017 solved 287 submit status discuss 一棵n個點的帶權有根樹,有p個詢問,每次詢問樹中是否存在一條長度為len的路徑,如果是,輸出yes否輸出no.第一行兩個整數n,p分別...

BZOJ 1316 樹上的詢問 點分治題解

time limit 10 sec memory limit 162 mb submit 738 solved 203 一棵n個點的帶權有根樹,有p個詢問,每次詢問樹中是否存在一條長度為len的路徑,如果是,輸出yes否輸出no.第一行兩個整數n,p分別表示點的個數和詢問的個數 接下來n 1行每行三...