bzoj1316(点分治)

题解

第一眼以为$q$很大…想了一晚上….

然后早上起来看题….$q<=100$ 惊了

好了 言归正传 $q<=100$那就直接暴力跑100次点分$ check $ 据说这样会被卡常数???反正我没试过

我们考虑 直接在重心分治的时候$check$ 每次把新的子树合并上去 然后$q$次$check$对应的$len$是否存在 然后我很快就$WA$了 原因是因为 $len=0$ 这种情况存在 特判下就能A了

复杂度 $O(qnlogn)$

代码实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdio>
#include <vector>
#include <stack>
#include <queue>
#include <cmath>
#include <set>
#include <map>
#define mp make_pair
#define pb push_back
#define pii pair<int,int>
#define link(x) for(edge *j=h[x];j;j=j->next)
#define inc(i,l,r) for(int i=l;i<=r;i++)
#define dec(i,r,l) for(int i=r;i>=l;i--)
const int MAXN=3e5+10;
const int NM=1e6+10;
const double eps=1e-8;
#define ll long long
using namespace std;
const int inf=1e9;
struct edge{int t,v;edge*next;}e[MAXN<<1],*h[MAXN],*o=e;
void add(int x,int y,int vul){o->t=y;o->v=vul;o->next=h[x];h[x]=o++;}
ll read(){
ll x=0,f=1;char ch=getchar();
while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
while(isdigit(ch))x=x*10+ch-'0',ch=getchar();
return x*f;
}

int p[MAXN],q,n,key,rt,base;
bool Num[NM],vis[MAXN],ans[MAXN];
int sz[MAXN],maxx[MAXN];

void get_root(int x,int pre){
sz[x]=1;maxx[x]=0;
link(x){
if(j->t==pre||vis[j->t])continue;
get_root(j->t,x);
sz[x]+=sz[j->t];maxx[x]=max(maxx[x],sz[j->t]);
}
maxx[x]=max(maxx[x],base-sz[x]);
if(key>maxx[x])rt=x,key=maxx[x];
}

int st[MAXN],St[MAXN],tot,tot1;
int dis[MAXN];


void dfs(int x,int pre){
if(dis[x]<NM)st[++tot]=dis[x],St[++tot1]=dis[x];
link(x){
if(j->t==pre||vis[j->t])continue;
dis[j->t]=dis[x]+j->v;
dfs(j->t,x);
}
}

void solve(int x){
tot1=0;Num[0]=1;vis[x]=1;
link(x){
if(vis[j->t])continue;
tot=0;dis[j->t]=j->v;dfs(j->t,x);
inc(i,1,tot)inc(k,1,q)if(st[i]<=p[k]&&Num[p[k]-st[i]])ans[k]=1;
inc(i,1,tot)Num[st[i]]=1;
}
inc(i,1,tot1)Num[St[i]]=0;Num[0]=0;
link(x){
if(vis[j->t])continue;
key=inf;base=sz[j->t];get_root(j->t,0);
solve(rt);
}
}


int main(){
inc(i,0,NM-1)Num[i]=0;
n=read();q=read();
int x,y,z;
inc(i,2,n)x=read(),y=read(),z=read(),add(x,y,z),add(y,x,z);
inc(i,1,q)p[i]=read();
key=inf;base=n;get_root(1,0);
solve(rt);
inc(i,1,q)if(!p[i]||ans[i])puts("Yes");else puts("No");
return 0;
}

题目描述

一棵$n$个点的带权有根树,有$p$个询问,每次询问树中是否存在一条长度为$Len$的路径,如果是,输出$Yes$否输出$No$.

Input

第一行两个整数$n, p$分别表示点的个数和询问的个数. 接下来$n-1$行每行三个数$x, y, c$,表示有一条树边$x→y$,长度为$c$. 接下来$p$行每行一个数$Len$,表示询问树中是否存在一条长度为$Len$的路径.

Output

输出有$p$行,$Yes$或$No$.