NOIP 2015 运输计划 树上差分 二分答案

15 篇文章 0 订阅
#include<bits/stdc++.h>
#define N 300010
#define INF 0x3f3f3f3f
#define eps 1e-10
#define pi 3.141592653589793
#define P 1000000007 
#define LL long long
#define pb push_back
#define fi first
#define se second
#define cl clear
#define si size
#define lb lower_bound
#define ub upper_bound
#define mem(x) memset(x,0,sizeof x)
#define sc(x) scanf("%d",&x)
#define scc(x,y) scanf("%d%d",&x,&y)
#define sccc(x,y,z) scanf("%d%d%d",&x,&y,&z)
using namespace std;

struct path{
    int s,t,lca,d;
}w[N];
struct edge{
    int u,v,nx;
}a[N<<1];

int cnt,n,m,mx,d[N],la[N],L[N],fa[N],anc[20][N],lg[N],v[N];
inline void add(int x,int y,int z){
    a[++cnt]=edge{y,z,la[x]};
    la[x]=cnt;
}

void dfs(int x,int ffa,int p){
    for (int i=la[x];i;i=a[i].nx){
        int u=a[i].u;
        if (u==ffa) continue;
        d[u]=d[x]+a[i].v;
        fa[u]=anc[0][u]=x;
        L[u]=p+1;
        for (int j=1;(1<<j)<=L[u];j++)
            anc[j][u]=anc[j-1][anc[j-1][u]];
        dfs(u,x,p+1);
    }
}

int query(int p,int q)
{
    if (L[p]<L[q]) swap(p,q);
    for (int i=19;i>=0;i--)
        if (L[p]-(1<<i)>=L[q])  p=anc[i][p];
    if (p==q)return p; 
    for (int i=19;i>=0;i--)
        if (anc[i][p] && anc[i][p]!=anc[i][q])
        p=anc[i][p],q=anc[i][q];
    return fa[p];
}

int spy(int x,int ffa){
    int t=0;
    for (int i=la[x];i;i=a[i].nx){
        int u=a[i].u;
        if (u==ffa) continue;
        t+=spy(u,x);
    }
    if (t+v[x]==cnt) mx=max(mx,d[x]-d[fa[x]]);
    return v[x]+t;
}

bool check(int tmp){
    memset(v,0,sizeof(int)*(n+2)); cnt=0; mx=-1; int mn=-1;
    for (int i=1;i<=m;i++) if (w[i].d>tmp){
        v[w[i].s]++;
        v[w[i].t]++;
        v[w[i].lca]-=2;
        cnt++; mn=max(mn,w[i].d);
    }
    if (!cnt) return 1;
    spy(n>>1,-1);
    if (mx==-1) return 0;
    if (mn-mx<=tmp) return 1;else return 0;
}

int main(){
    scc(n,m);
    for (int i=1,x,y,z;i<n;i++){
        sccc(x,y,z);
        add(x,y,z); add(y,x,z);
    }
    for (int i=1;i<=m;i++) scc(w[i].s,w[i].t);

    dfs(n>>1,-1,0);
    
    for (int i=1;i<=m;i++){
        w[i].lca=query(w[i].s,w[i].t);
        w[i].d=d[w[i].s]+d[w[i].t]-d[w[i].lca]*2;
    }

    int l=0,r=3e8,ans;
    while(l<=r){
        int t=(l+r)>>1;
        if (check(t))
            ans=t,r=t-1;else l=t+1;
    }
    printf("%d\n",ans);
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值