前言
WARNING:代码有点问题!但是懒得改了!
好久没见过这么优雅的暴力了,这不学后悔一生啊!
说实话,还不太会。
讲解
其实就是改变一下树的遍历顺序,然后做到 (O(nlogn)) 的时间复杂度
大概的思路是:
对于一棵树,我们找到它的重心,以其为根向下延伸,然后对于它的子树我们也做这样的操作,找到它们的重心作为其新的儿子。由于我们改变了遍历顺序,所以我们要用 (vis) 数组将已经经过的点打上标记。
经典操作是对于每个点,我们可以遍历其整棵子树,然后用一些操作更新答案,通常我们见到的操作可以用 数据结构 或者 two pointers 更新。这样的时间复杂度是正确的 (O(nlogn)),多么优雅的暴力,不是吗。
具体的可以看板题代码。
练习
代码
板题代码。
int head[MAXN],tot;
struct edge
{
int v,w,nxt;
}e[MAXN << 1];
void Add_Edge(int x,int y,int z)
{
e[++tot].v = y;
e[tot].w = z;
e[tot].nxt = head[x];
head[x] = tot;
}
void Add_Double_Edge(int x,int y,int z)
{
Add_Edge(x,y,z);
Add_Edge(y,x,z);
}
bool vis[MAXN];
int siz[MAXN],MAX[MAXN];
void getrt(int x,int fa,int S)//找重心
{
siz[x] = 1;
MAX[x] = 0;
for(int i = head[x]; i ;i = e[i].nxt)
{
if(e[i].v == fa || vis[e[i].v]) continue;
getrt(e[i].v,x,S);
siz[x] += siz[e[i].v];
MAX[x] = Max(MAX[x],siz[e[i].v]);
}
MAX[x] = Max(MAX[x],S-siz[x]);
if(!rt || MAX[x] < MAX[rt]) rt = x;
}
int cnt;
int p[MAXN],bl[MAXN],dis[MAXN];
void getdis(int x,int fa,int D,int from)
{
p[++cnt] = x;
bl[x] = from;
dis[x] = D;
for(int i = head[x]; i ;i = e[i].nxt)
if(e[i].v != fa && !vis[e[i].v])
getdis(e[i].v,x,D+e[i].w,from);
}
bool cmp(int x,int y){return dis[x] < dis[y];}
void update(int x)
{
cnt = 0;
p[++cnt] = x;
bl[x] = x;
dis[x] = 0;
for(int i = head[x]; i ;i = e[i].nxt)
if(!vis[e[i].v]) getdis(e[i].v,x,e[i].w,e[i].v);
sort(p+1,p+cnt+1,cmp);
for(int i = 1;i <= Q;++ i)
{
if(aye[i]) continue;
int l = 1,r = cnt;
while(l < r)
{
if(dis[p[l]] + dis[p[r]] < q[i]) l++;
else if(dis[p[l]] + dis[p[r]] > q[i]) r--;
else if(bl[p[l]] == bl[p[r]])
{
if(bl[p[r]] == bl[p[r-1]]) r--;
else l++;
}
else
{
aye[i] = 1;
break;
}
}
}
}
void solve(int x)
{
vis[x] = 1;
//应该在这个位置重新跑一遍dfs更新siz
update(x);
for(int i = head[x]; i ;i = e[i].nxt)
{
if(vis[e[i].v]) continue;
rt = 0;//记得初始化!
getrt(e[i].v,x,siz[e[i].v]);//这里的siz没更新,有点问题
solve(rt);
}
}
int main()
{
// freopen(".in","r",stdin);
// freopen(".out","w",stdout);
n = Read(); Q = Read();
for(int i = 1,u,v;i < n;++ i) u = Read(),v = Read(),Add_Double_Edge(u,v,Read());
for(int i = 1;i <= Q;++ i)
{
q[i] = Read();
if(!q[i]) aye[i] = 1;
}
getrt(1,0,n);
solve(rt);
for(int i = 1;i <= Q;++ i)
{
if(aye[i]) printf("AYE
");
else printf("NAY
");
}
return 0;
}