P2680 [NOIP2015 提高组] 运输计划
[NOIP2015 提高组] 运输计划
题目背景
公元
题目描述
公元
L 国有
小 P 掌管一家物流公司, 该公司有很多个运输计划,每个运输计划形如:有一艘物流飞船需要从
为了鼓励科技创新, L 国国王同意小 P 的物流公司参与 L 国的航道建设,即允许小 P 把某一条航道改造成虫洞,飞船驶过虫洞不消耗时间。
在虫洞的建设完成前小 P 的物流公司就预接了
如果小 P 可以自由选择将哪一条航道改造成虫洞, 试求出小 P 的物流公司完成阶段性工作所需要的最短时间是多少?
输入格式
第一行包括两个正整数
接下来
数据保证
接下来
输出格式
一个整数,表示小 P 的物流公司完成阶段性工作所需要的最短时间。
样例 #1
样例输入 #1
6 3
1 2 3
1 6 4
3 1 7
4 3 6
3 5 5
3 6
2 5
4 5
样例输出 #1
11
提示
所有测试数据的范围和特点如下表所示
请注意常数因子带来的程序效率上的影响。
对于
Solution
一道树上差分的好的练手题。
先说明题意:求将树上一条边的边权设置为
看到这种求的又是最大又是最小的题,基本都可以往二分答案想。此题的答案显然是具有单调性的,也就是说可以用二分答案解决。
考虑知道了最长路径的最小值,如何验证答案。显然每条路径的长度都可以通过预处理
现在考虑如何实现覆盖的操作(类似于区间加),可以用树剖
所以就可以很轻松的写出代码了。
Code
#include<bits/stdc++.h>
#define mem(a,b) memset(a,b,sizeof a)
//#define int long long
using namespace std;
template<typename T> void read(T &k)
{
k=0;T flag=1;char b=getchar();
while (!isdigit(b)) {flag=(b=='-')?-1:1;b=getchar();}
while (isdigit(b)) {k=k*10+b-48;b=getchar();}
k*=flag;
}
template<typename T> void write(T k) {if (k<0) {putchar('-'),write(-k);return;}if (k>9) write(k/10);putchar(k%10+48);}
template<typename T> void writewith(T k,char c) {write(k);putchar(c);}
const int _SIZE=3e5;
struct EDGE{
int nxt,to,l;
}edge[(_SIZE<<1)+5];
int tot,head[_SIZE+5];
void AddEdge(int x,int y,int l) {edge[++tot]=(EDGE){head[x],y,l};head[x]=tot;}
struct LINK{
int x,y,lca;
}l[_SIZE+5];
int n,m,f[_SIZE+5][25],dep[_SIZE+5],dis[_SIZE+5],pre[_SIZE+5];
void dfsForLca(int x,int fa)
{
f[x][0]=fa,dep[x]=dep[fa]+1;
for (int i=1;i<=20;i++) f[x][i]=f[f[x][i-1]][i-1];
for (int i=head[x];i;i=edge[i].nxt)
{
int twd=edge[i].to;
if (twd==fa) continue;
dis[twd]+=dis[x]+edge[i].l;
pre[twd]=edge[i].l;
dfsForLca(twd,x);
}
}
int LCA(int x,int y)
{
if (dep[x]<dep[y]) swap(x,y);
for (int i=0,temp=dep[x]-dep[y];temp;i++,temp>>=1) if (temp&1) x=f[x][i];
if (x==y) return x;
for (int i=20;i>=0;i--) if (f[x][i]!=f[y][i]) x=f[x][i],y=f[y][i];
return f[x][0];
}
bool flag=0;
int diff[_SIZE+5];
int judge(int x,int fa,int cnt,int maxn)
{
int curSum=diff[x];
for (int i=head[x];i;i=edge[i].nxt)
{
int twd=edge[i].to;
if (twd==fa) continue;
curSum+=judge(twd,x,cnt,maxn);
}
if (curSum>=cnt && pre[x]>=maxn) flag=1;
return curSum;
}
bool check(int limit)
{
mem(diff,0);
int cnt=0,maxn=0;flag=0;
for (int i=1;i<=m;i++)
{
int x=l[i].x,y=l[i].y,lca=l[i].lca;
if (dis[x]+dis[y]-2*dis[lca]>limit)
{
diff[x]++,diff[y]++,diff[lca]-=2;cnt++;
maxn=max(maxn,dis[x]+dis[y]-2*dis[lca]);
}
}
if (cnt==0) return 1;
judge(1,0,cnt,maxn-limit);
return flag;
}
signed main()
{
read(n);read(m);
for (int i=1;i<n;i++)
{
int u,v,l;read(u),read(v),read(l);
AddEdge(u,v,l),AddEdge(v,u,l);
}
dfsForLca(1,0);
for (int i=1;i<=m;i++)
{
read(l[i].x),read(l[i].y);
l[i].lca=LCA(l[i].x,l[i].y);
}
int l=0,r=3e8;
while (l<r)
{
int mid=(l+r)>>1;
if (check(mid)) r=mid;
else l=mid+1;
}
writewith(l,'\n');
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步