绝对是一个全新的暴力思路。~只不过要开O2才能过。
接下来进入正题。
看到有一条边可以变成0,很自然地就想到要删边。
那么怎么判断一条边是不是在一条路径上呢?
设一条边的两个端点为u,v;
那条路径的两个端点为x,y;
我们把这个问题拆成两个小问题来做,
1先判定一个点是不是在那条路径上;
2再判断另一个点是不是也在那条路径上;
判定一个点是不是在一条路径上满足如下等式即可
设dis(i,j)为两点间的最短距离
dis(u,x)+dis(u,y)==dis(x,y)
至于证明用反证法
解决了这个之后接下来的就都是暴力了
细节会在代码里标注
#include<bits/stdc++.h>
using namespace std;
const int ll=1e6;
int head[ll],next[ll],uer[ll],ver[ll],wer[ll],tot;
int f[ll][30],d[ll],dis[ll],t;
void read(int &t)//偷来的快读
{
char ch;
while(ch = getchar())
if(ch>='0' && ch<='9')
break;
t = ch - '0';
while(ch = getchar())
if(ch>='0' && ch<='9')
t = (t<<3)+(t<<1)+ch-'0';
else break;
}
void add(int u,int v,int w){//前向星存图
tot++;
uer[tot]=u;
ver[tot]=v;
wer[tot]=w;
next[tot]=head[u];
head[u]=tot;
}
int n,m;
void bfs(){
queue<int> q;
q.push(1);
while(q.size()){
int x=q.front();
q.pop();
for(int i=head[x]; i ; i=next[i]){
int y=ver[i],w=wer[i];
if(d[y]) continue;
d[y]=d[x]+1;
dis[y]=dis[x]+w;
f[y][0]=x;
for(int j=1;j<=t;j++)
f[y][j]=f[f[y][j-1]][j-1];
q.push(y);
}
}
}
int lca(int x,int y){
if(d[x]<d[y]) swap(x,y);
for(int i=t;i>=0;i--)
if(d[f[x][i]]>=d[y])
x=f[x][i];
if(x==y) return x;
for(int i=t;i>=0;i--)
if(f[x][i]!=f[y][i])
x=f[x][i],y=f[y][i];
return f[x][0];
}
struct jh{
int u,v,w;
}a[ll];//保存路径的起点,终点和长度
bool cmp(jh a,jh b){
return a.w>b.w;
}
bool pd(int a,int b,int c,int len){
return 2*dis[a]+dis[b]+dis[c]-2*(dis[lca(a,b)]+dis[lca(a,c)])==len;
}
int main(){
read(n); read(m);
for(int i=1;i<=n-1;i++){
int u,v,w;
read(u); read(v); read(w);
add(u,v,w);
add(v,u,w);
}
t=log(n)/log(2)+1;
d[1]=1;
bfs();
for(int i=1;i<=m;i++){
read(a[i].u); read(a[i].v);
a[i].w=dis[a[i].u]+dis[a[i].v]-2*dis[lca(a[i].u,a[i].v)];
}
int ans=1<<30;
sort(a+1,a+m+1,cmp);//把计划按照长度从大到小排序,
for(int i=1;i<=2*(n-1);i+=2){
int x=uer[i],y=ver[i],w=wer[i];//枚举删边
int sum=0;
for(int j=1;j<=m;j++){//由于路径长度是从大到小的,
int flag=0; //一旦sum不可能再被更新立即退出。
int u=a[j].u,v=a[j].v;
int fa=lca(u,v);
int len=dis[u]+dis[v]-2*dis[fa];
if(pd(x,u,v,len)&&pd(y,u,v,len)){
if(sum<len-w)
sum=len-w;
flag=1;
if(sum>ans) break;
}
else{
if(sum<len){
sum=len;
}
}
if(!flag) break;
}
ans=min(ans,sum);
}
printf("%d",ans);
return 0;
}