H 国有 n个城市,这 n 个城市用n−1条双向道路相互连通构成一棵树,1号城市是首都,也是树中的根节点。
H国的首都爆发了一种危害性极高的传染病。当局为了控制疫情,不让疫情扩散到边境城市(叶子节点所表示的城市),决定动用军队在一些城市建立检查点,使得从首都到边境城市的每一条路径上都至少有一个检查点,边境城市也可以建立检查点。但特别要注意的是,首都是不能建立检查点的。
现在,在 H 国的一些城市中已经驻扎有军队,且一个城市可以驻扎多个军队。一支军队可以在有道路连接的城市间移动,并在除首都以外的任意一个城市建立检查点,且只能在一个城市建立检查点。一支军队经过一条道路从一个城市移动到另一个城市所需要的时间等于道路的长度(单位:小时)。
请问最少需要多少个小时才能控制疫情。注意:不同的军队可以同时移动。
一看就很可以二分的样子
然后得到时间后我们每个军队都一定是要往上走的,一种是还没走到根节点就停下了,还有一种是走到根节点后可以往下走
这个可以预处理倍增出来,处理出能走到根节点的军队和剩余距离
然后我们在现在走完的图上dfs一遍找出根节点的儿子中没有被控制的点,再记录下到根节点的距离
因为我们填这些没有被控制的节点肯定是剩余路程多的军队走到里根节点远的距离
所以可以对没被控制的节点和可以移动的军队排个序
但是在选的时候还有一种情况就是这个点的子树里有能跳上根的军队,所以我们还要维护每个子树里能调到根的剩余路径最小的军队
去控制点的时候先看看子树里最小的军队有没有被使用,被使用了就去找排好序里可以用的军队
然后就做完了,时间复杂度(O(nlog^2n))
Code
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <vector>
const long long INF = 1e14;
const int inf = 1e9;
const int N = 5e4;
const int log = 16;
using namespace std;
struct node
{
int to,cost;
};
struct army
{
int u;
long long len;
}a[N + 5];
struct sos
{
int u,l;
}b[N + 5];
struct near
{
int u;
long long ml;
}c[N + 5];
int used[N + 5],n,m,in[N + 5],fa[N + 5][log + 2],na,nb,to[N + 5],t[N + 5],beat[N + 5],cnt;
long long dis[N + 5][log + 2],ans = -1;
vector <node> d[N + 5];
void dfs(int u,int f)
{
fa[u][0] = f;
for (int i = 1;i <= log;i++)
fa[u][i] = fa[fa[u][i - 1]][i - 1],dis[u][i] = dis[u][i - 1] + dis[fa[u][i - 1]][i - 1];
vector <node>::iterator it;
for (it = d[u].begin();it != d[u].end();it++)
{
int v = (*it).to,w = (*it).cost;
if (v == f)
continue;
dis[v][0] = w;
dfs(v,u);
}
}
void search(int u,int f)
{
beat[u] = t[u];
vector <node>::iterator it;
int fl = 1;
if (d[u].size() == 1)
fl = 0;
for (it = d[u].begin();it != d[u].end();it++)
{
int v = (*it).to;
if (v == f)
continue;
search(v,u);
fl &= beat[v];
}
beat[u] |= fl;
}
int cmpa(army x,army y)
{
return x.len > y.len;
}
int cmpb(sos x,sos y)
{
return x.l > y.l;
}
int check(long long x)
{
memset(t,0,sizeof(t));
memset(beat,0,sizeof(beat));
memset(used,0,sizeof(used));
for (int i = 1;i <= n;i++)
c[i].ml = INF;
na = nb = 0;
for (int i = 1;i <= m;i++)
{
int u = in[i];
long long res = x;
for (int j = log;j >= 0;j--)
if (res >= dis[u][j] && fa[u][j] > 1)
{
res -= dis[u][j];
u = fa[u][j];
}
if (fa[u][0] == 1 && res >= dis[u][0])
{
res -= dis[u][0];
a[++na] = (army){i,res};
if (c[u].ml > res)
c[u].ml = res,c[u].u = i;
u = 1;
}
t[u] = 1;
}
vector <node>::iterator it;
beat[1] = 1;
for (it = d[1].begin();it != d[1].end();it++)
{
int v = (*it).to,w = (*it).cost;
search(v,1);
beat[1] &= beat[v];
if (beat[v] == 0)
b[++nb] = (sos){v,w};
}
if (beat[1])
return 1;
sort(a + 1,a + na + 1,cmpa);
sort(b + 1,b + nb + 1,cmpb);
int l = 1;
for (int i = 1;i <= nb;i++)
{
if (!used[c[b[i].u].u] && c[b[i].u].ml != INF)
used[c[b[i].u].u] = 1;
else
{
while ((used[a[l].u] || a[l].len < b[i].l) && l <= na)
l++;
if (l > na)
return 0;
used[a[l].u] = 1;
}
}
return 1;
}
int main()
{
scanf("%d",&n);
int u,v,w;
for (int i = 1;i < n;i++)
{
scanf("%d%d%d",&u,&v,&w);
d[u].push_back((node){v,w});
d[v].push_back((node){u,w});
}
dfs(1,0);
scanf("%d",&m);
for (int i = 1;i <= m;i++)
scanf("%d",&in[i]);
long long l = 0,r = INF,mid;
while (l <= r)
{
mid = l + r >> 1;
if (check(mid))
r = mid - 1,ans = mid;
else
l = mid + 1;
}
cout<<ans<<endl;
return 0;
}