一棵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行每行三...