Description
给你一棵n个点的带权有根树,有p个询问,每次询问树中是否存在一条长度为Len的路径,如果是,输出Yes否输出No.
Input
第一行两个整数n, p分别表示点的个数和询问的个数. 接下来n-1行每行三个数x, y, c,表示有一条树边x→y,长度为c. 接下来p行每行一个数Len,表示询问树中是否存在一条长度为Len的路径.
Output
输出有p行,Yes或No.
Sample Input
6 4
1 2 5
1 3 7
1 4 1
3 5 2
3 6 3
1
8
13
14
Sample Output
Yes
Yes
No
Yes
【数据范围】
30%的数据,n≤100.
100%的数据,n≤10000,p≤100,长度≤100000.
和POJ题目一样???我在POJ 可以AC,BZOJ死活AC不了啊,有路过A了的大神求助。下面的代码在POJ能
AC。
只需将“不超过k”改为“不超过k减去小于k”,就可以得到“等于k”的数量了。
///BZOJ 1460
#include <vector>
#include <stdio.h>
#include <string.h>
#include <iostream>
#include <algorithm>
using namespace std;
const int maxn = 10010;
typedef long long LL;
struct edge
{
int to;
LL length;
};
int n,k;
vector<edge>G[maxn];
bool centroid[maxn];///顶点是否已作为重心删除的标记
int subtree_size[maxn];///以该顶点为根的子树的大小(查找重心时用)
LL ans;
///以该顶点为根的子树的大小(查找重心时用)
int compute_subtree_size(int v, int p)
{
int c=1;
for(int i=0; i<G[v].size(); i++)
{
int w=G[v][i].to;
if(w==p||centroid[w]) continue;
c+=compute_subtree_size(G[v][i].to, v);
}
subtree_size[v]=c;
return c;
}
///查找重心的递归函数,t是整个连通分量的大小
///在以v为根的子树中寻找一个顶点,使得删除该顶点后最大子树的顶点数最小
///返回值为pair(最大子树的顶点数,顶点编号)
pair<int, int>search_centroid(int v, int p, int t)
{
pair<int, int>res = make_pair(0x3f3f3f3f, -1);
int s=1, m=0;
for(int i=0; i<G[v].size(); i++)
{
int w=G[v][i].to;
if(w==p||centroid[w]) continue;
res = min(res, search_centroid(w, v, t));
m=max(m, subtree_size[w]);
s+=subtree_size[w];
}
m=max(m,t-s);
res=min(res,make_pair(m,v));
return res;
}
void enumerate_paths(int v, int p, int d, vector<int>&ds)
{
ds.push_back(d);
for(int i=0; i<G[v].size(); i++)
{
int w=G[v][i].to;
if(w==p||centroid[w]) continue;
enumerate_paths(w, v, d+G[v][i].length, ds);
}
}
int count_pairs(vector<int>&ds)
{
int res=0;
sort(ds.begin(),ds.end());
int j=ds.size();
for(int i=0; i<ds.size(); i++)
{
while(j>0&&ds[i]+ds[j-1]>k) j--;///除去和本身组成的点对
res+=j-(j>i?1:0);
}
j=ds.size();
for(int i=0; i<ds.size(); i++)
{
while(j>0&&ds[i]+ds[j-1]>=k) j--;
res-=j-(j>i?1:0);
}
return res;
}
void solve_subproblem(int v)
{
compute_subtree_size(v,-1);
int s=search_centroid(v,-1,subtree_size[v]).second;
centroid[s] = true;
///统计按顶点s分割后子树中的对数
for (int i = 0; i < G[s].size(); i++)
{
if (centroid[G[s][i].to])
continue;
solve_subproblem(G[s][i].to);
}
///统计经过点s的对数
static vector<int> ds;
ds.clear();
ds.push_back(0);
for (int i = 0; i < G[s].size(); i++)
{
if (centroid[G[s][i].to])
continue;
static vector<int> tds;
tds.clear();
enumerate_paths(G[s][i].to, s, G[s][i].length, tds);
ans -= count_pairs(tds);
ds.insert(ds.end(), tds.begin(), tds.end());
}
ans += count_pairs(ds);
centroid[s]=false;
}
int main()
{
int p;
while(scanf("%d%d", &n,&p)!=EOF){
for(int i=0; i<n; i++) G[i].clear();
for(int i=1; i<n; i++){
int u, v;
LL c;
scanf("%d%d%lld", &u,&v,&c);
G[u-1].push_back({v-1,c});
G[v-1].push_back({u-1,c});
}
while(p--){
scanf("%d", &k);
ans=0;
memset(centroid, 0, sizeof(centroid));
solve_subproblem(0);
if(ans>0) puts("Yes\n");
else puts("No\n");
}
}
return 0;
}