[luogu 4886] 快递员

[luogu 4886] 快递员

传送门

Solution

虽然不是点分治但用类似点分治的方法不断接近正确结果

Code

// luogu-judger-enable-o2
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <algorithm>
#define F(i,a,b) for(register int i=(a);i<=(b);i++)
#define R(i,a,b) for(register int i=(b);i>=(a);i--)
#define E(i,u) for(register int i=head[u],v;i;i=nxt[i])
#define add(a,b,c) nxt[++cnt]=head[a],to[cnt]=b,cst[cnt]=c,head[a]=cnt
#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin)),p1==p2?EOF:*p1++)
using namespace std;

char buf[1<<22],*p1,*p2;
inline int read() {
    int x=0,f=1;char c=getchar();
    while(!isdigit(c)) {if(c=='-')f=-f;c=getchar();}
    while(isdigit(c)) x=(x<<1)+(x<<3)+(c^48),c=getchar();
    return x*f;
}

const int N=1e5+10,INF=2147483647;
int n,m,cnt,bary,ans,maxx,tot;
bool vis[N];
int l[N],r[N],siz[N],dis[N],bel[N],sum[N];
int nxt[N<<1],to[N<<1],cst[N<<1],head[N];

inline void get_siz(int u,int pre) {
    siz[u]=1;
    E(i,u) if((v=to[i])!=pre&&!vis[v]) 
        get_siz(v,u),siz[u]+=siz[v];
}

inline void get_dis(int u,int pre,int rt) {
    bel[u]=rt;
    E(i,u) if((v=to[i])!=pre) //不加!vis[v]
        dis[v]=dis[u]+cst[i],get_dis(v,u,rt);
}

inline void find_bary(int u,int pre) {
    int mx=0; siz[u]=1;
    E(i,u) if((v=to[i])!=pre&&!vis[v]) 
        find_bary(v,u),mx=max(mx,siz[v]),siz[u]+=siz[v];
    mx=max(mx,tot-siz[u]);
    if(!bary||mx<maxx) maxx=mx,bary=u;
}

inline void solve(int rt) {
    int mx=0,tar=-1; 
    vis[rt]=1; dis[rt]=0; bel[rt]=rt;
    E(i,rt) dis[(v=to[i])]=cst[i],get_dis(v,rt,v);
    F(i,1,m) mx=max(mx,(sum[i]=dis[l[i]]+dis[r[i]]));
    ans=min(ans,mx);
    F(i,1,m) if(sum[i]==mx) {
        if(bel[l[i]]!=bel[r[i]]) return ;
        if((~tar)&&tar!=bel[l[i]]) return ;
        tar=bel[l[i]];
    }
    if(vis[tar]) return ;
    get_siz(tar,rt); tot=siz[tar];
    bary=maxx=0; find_bary(tar,rt);
    solve(bary);
}

int main() {
    n=read(),m=read(),ans=INF;
    F(i,1,n-1) {
        int a=read(),b=read(),c=read();
        add(a,b,c); add(b,a,c);
    }
    F(i,1,m) l[i]=read(),r[i]=read();
    tot=n; solve(1);
    printf("%d",ans);
    return 0;
}
posted @ 2018-10-02 23:33 Menteur_Hxy 阅读( ...) 评论( ...) 编辑 收藏
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值