你最愿意做的哪件事,才是你的天赋所在

0%

点分治-luogu3806

题目链接

luogu3806

思路

这题是点分治的模板题目,点分治就是一棵树上的分治。
详细的教程上B站看AgOH的直播,很感谢大佬的分享
点分治教程-作者:AgOH

代码实现

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
88
89
90
91
92
93
94
95
96
#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int N = 1e4+10;
const int NN = 1e7+10;
struct edge{
int v,dis,nex;
}edges[N<<1];
int head[N<<1],edgenum,sum,rt,n,m,cnt;
int maxp[N],siz[N],dis[N],q[N/10],tmp[N<<1];
bool ans[NN],judge[NN],vis[N];
void add(int u,int v,int dis){
edges[edgenum].nex=head[u];
edges[edgenum].v=v;
edges[edgenum].dis=dis;
head[u]=edgenum++;
}
void getrt(int u,int fa){
siz[u]=1,maxp[u]=0;
for(int i=head[u];~i;i=edges[i].nex){
int v = edges[i].v;
if(vis[v]||v==fa)continue;
getrt(v,u);
siz[u]+=siz[v];
if(maxp[u]<siz[v])maxp[u]=siz[v];
}
maxp[u]=max(maxp[u],sum-siz[u]);
if(maxp[u]<maxp[rt])rt=u;
}
void getdis(int u,int f){
tmp[cnt++]=dis[u];
for(int i=head[u];~i;i=edges[i].nex){
int v = edges[i].v;
if(v==f||vis[v])continue;
dis[v]=dis[u]+edges[i].dis;
getdis(v,u);
}
}
void solve(int u){
queue<int>que;
for(int i=head[u];~i;i=edges[i].nex){
int v = edges[i].v;
if(vis[v])continue;
cnt = 0;
dis[v]=edges[i].dis;
getdis(v,u);
for(int j=0;j<cnt;j++){
for(int k=0;k<m;k++){
if(q[k]>=tmp[j]){
ans[k]|=judge[q[k]-tmp[j]];
}
}
}
for(int j=0;j<cnt;j++){
que.push(tmp[j]);
judge[tmp[j]]=1;
}
}
while (!que.empty()){
judge[que.front()]=false;
que.pop();
}
}
void divide(int u){
vis[u]=judge[0]=1;
solve(u);//计算经过根节点的路径
for(int i=head[u];~i;i=edges[i].nex){
int v = edges[i].v;
if(vis[v])continue;
maxp[rt=0]=sum=siz[v];
getrt(v,0);
// 这里第二次做获重心是为了得到正确的size数组,防止下次操作的时候错误
getrt(rt,0);
divide(rt);
}
}
int main(){
memset(head,-1,sizeof(head));
scanf("%d %d",&n,&m);
for(int i=0;i<n-1;i++){
int u,v,w;
scanf("%d %d %d",&u,&v,&w);
add(u,v,w);
add(v,u,w);
}
for(int i=0;i<m;i++)scanf("%d",&q[i]);
maxp[0]=sum=n;
getrt(1,0);
getrt(rt,0);
divide(rt);
for(int i=0;i<m;i++){
if(ans[i])printf("AYE\n");
else printf("NAY\n");
}
return 0;
}
-------------你最愿意做的哪件事才是你的天赋所在-------------