点分治神题orzorz

首先考虑O(nm)O(nm)的暴力,就是枚举任意点作为邮递站作根,暴力dfsdfs,求出每组配送的最大代价,记作cost_icosti

那么对于最优点作根,显然对于任意一条从根开始的链,cost_icosti都是递增的

于是我们可以点分治一下,每次做出当前子树的重心,对所有配送都求一遍代价,取maxmax

对于一次配送,若其代价为maxmax,并且两点跨过重心,或者多组配送在重心的不同子树,代价均为maxmax,显然此时是最优点

否则迭代着继续点分治,显然只有loglog次

复杂度为O(mlogn)O(mlogn)

#include<cstdio>
#include<algorithm>
#include<cstdlib>
#define rep(i,s,t) for(register int i=s;i<=t;++i)
#define gi(x) read(x)
#define gii(x,y) read(x),read(y)
#define giii(x,y,z) read(x),read(y),read(z)
#define ms(f,x) memset(f,x,sizeof f)
#define open(x) freopen(#x".in","r",stdin),freopen(#x".out","w",stdout)
namespace IO{
    #define gc getchar()
    #define pc(x) putchar(x)
    template<typename T>inline void read(T &x){
        x=0;int f=1;char ch=gc;while(ch>'9'||ch<'0'){if(ch=='-')f=-1;ch=gc;}
        while(ch>='0'&&ch<='9')x=(x<<3)+(x<<1)+ch-'0',ch=gc;x*=f;return;
    }
    template<typename T>inline void write(T x=0){
        T wr[51];wr[0]=0;if(x<0)pc('-'),x=-x;if(!x)pc(48);
        while(x)wr[++wr[0]]=x%10,x/=10;while(wr[0])pc(48+wr[wr[0]--]);return;
    }
}
using IO::read;
using IO::write;
using namespace std;
const int N=2e5+11;
int n,m,tot,rt,ans;
int nxt[N],las[N],to[N],w[N],sz[N],f[N],bel[N],dis[N],p[N];
int x[N],y[N];
bool vis[N];
inline void add(int x,int y,int z){
    nxt[++tot]=las[x];
    las[x]=tot;
    to[tot]=y;
    w[tot]=z;
}
inline void getroot(int x,int fa,int siz){
    sz[x]=1;f[x]=0;
    for(register int e=las[x];e;e=nxt[e]){
        if(to[e]==fa||vis[to[e]])continue;
        getroot(to[e],x,siz);
        sz[x]+=sz[to[e]];
        f[x]=max(f[x],sz[to[e]]);
    }
    f[x]=max(f[x],siz-sz[x]);
    if(f[x]<f[rt])rt=x;
}
inline void dfs(int x,int fa,int rt){
    bel[x]=rt;
    for(register int e=las[x];e;e=nxt[e]){
        if(to[e]==fa)continue;
        dis[to[e]]=dis[x]+w[e];
        dfs(to[e],x,rt);
    }
}
inline void solve(int u){
    if(vis[u]){
        printf("%d\n",ans);
        exit(0);
    }
    vis[u]=1,dis[u]=0;
    for(register int e=las[u];e;e=nxt[e])
        dis[to[e]]=w[e],dfs(to[e],u,to[e]);
    int Max=0,las=0;p[0]=0;
    rep(i,1,m)
        if(dis[x[i]]+dis[y[i]]>Max)
            Max=dis[x[i]]+dis[y[i]],p[p[0]=1]=i;
        else
            if(Max==dis[x[i]]+dis[y[i]])
                p[++p[0]]=i;
    ans=min(ans,Max);
    rep(i,1,p[0])
        if(bel[x[p[i]]]!=bel[y[p[i]]]){
            printf("%d\n",ans);
            exit(0);
        }
        else{
            if(!las)las=bel[x[p[i]]];
            else 
                if(bel[x[p[i]]]!=las){
                    printf("%d\n",ans);
                    exit(0);
                }
        }
    rt=0;
    getroot(las,u,sz[las]);
    solve(rt);
}
int main(){
    gii(n,m);
    rep(i,2,n){
        int u,v,w;
        giii(u,v,w);
        add(u,v,w),add(v,u,w);
    }
    rep(i,1,m)
        gii(x[i],y[i]);
    ans=1e9;
    f[rt=0]=n+1;
    getroot(1,1,n);
    solve(rt);
    return 0;
}