P2680 [NOIP2015 提高组] 运输计划

一棵树,数值有权值,m条运输路线,问将一条边换为0 使运输路线最大值最小

》最大值最小-》二分

》路线长度+树-》LCA

》》二分->正确答案->所有大于mid的路径 都有k公共边 使得 len-k<=mid

:::树上差分 标记公共点 lca-=2 u-=2 v-=2 每次重新标记

:::dis 与 dep ->dep->lca   /dis->len

:::二分时 左偏 left=mid+1  && r+1  因为边不一定等差递增

#include<cstdio>
#include<iostream>
#include<algorithm>
//#include<queue>
//#include<vector>
#include<bits/stdc++.h>
#define ll long long
#define ddd printf("-----------------------\n");
using namespace std;
const int maxn=3e5+10;

struct line{
    int u,v,lca,len;
}lu[maxn<<1];
int head[maxn],to[maxn<<1],nxt[maxn<<1],w[maxn<<1],tot;
int dep[maxn],dis[maxn<<1],f[maxn][25],num[maxn],dfstm,tmp[maxn];
int n,m,sum,rgt,lft;

void add(int u,int v,int val){
    to[++tot]=v,nxt[tot]=head[u],head[u]=tot,w[tot]=val;
}
void dfs(int u,int fa)
{
    dep[u]=dep[fa]+1; f[u][0]=fa; num[++dfstm]=u;
    for(int i=1;i<=24;i++) f[u][i]=f[f[u][i-1]][i-1];
    for(int i=head[u];i;i=nxt[i])
    {
        int v=to[i];if(v==fa) continue;
        dis[v]=dis[u]+w[i];
        dfs(v,u);
    }
}
int LCA (int x,int y)
{
    if(dep[x]<dep[y]) swap(x,y);
    for(int i=24;i>=0;i--)//二进制诬陷分割 
    {
        if(dep[f[x][i]]>=dep[y]) x=f[x][i];
        if(x==y) return x;
    }
    for(int i=24;i>=0;i--)
    {
        if(f[x][i]!=f[y][i])
        {
            x=f[x][i];
            y=f[y][i];
        }
    }
    return f[x][0];
}
int check(int mid)
{
    int cnt=0,chaju=0;
    memset(tmp,0,sizeof(tmp));
    
    for(int i=1;i<=m;i++){
        if(lu[i].len>mid)//
        {
            tmp[lu[i].u]++,tmp[lu[i].v]++,tmp[lu[i].lca]-=2;//
            cnt++;
            chaju=max(chaju,lu[i].len-mid);
        }
    }
    if(cnt==0) return 1;/////!!!!!!!!
    for(int i=n;i>=1;i--) tmp[ f[num[i]][0] ]+=tmp[num[i]];
    for(int i=2;i<=n;i++){//!!!!!!!
        if(tmp[i]==cnt&&dis[i]-dis[f[i][0]]>=chaju) return 1;
    }
    return 0;
}
int main()
{
    ios::sync_with_stdio(false);
    cin>>n>>m;
    for(int i=1;i<=n-1;i++){
        int u,v,val;cin>>u>>v>>val;
        add(u,v,val);add(v,u,val);
        sum+=val;
    }
    dis[1]=0;
    dfs(1,0);
    for(int i=1;i<=m;i++){
        cin>>lu[i].u>>lu[i].v;
        lu[i].lca=LCA(lu[i].u,lu[i].v);
        lu[i].len=dis[lu[i].v]+dis[lu[i].u]-2*dis[lu[i].lca];
    }
    rgt=sum+2,lft=0;//左偏建议右+1 
    while(lft<rgt)
    {
        int mid=lft+rgt>>1;
        if(check(mid)) rgt=mid;
        else lft=mid+1;
    }
    cout<<lft<<'\n';
    
    return 0;
}

 

posted @ 2023-09-09 15:07  JMXZ  阅读(16)  评论(0)    收藏  举报