[NOIP2015]運輸計劃 題解

題目背景

公元 2044 年,人類進入了宇宙紀元。ios

題目描述

L 國有 n 個星球,還有 n-1 條雙向航道,每條航道創建在兩個星球之間,這 n-1 條git

航道連通了 L 國的全部星球。ui

小 P 掌管一家物流公司,該公司有不少個運輸計劃,每一個運輸計劃形如:有一艘物spa

流飛船須要從 ui 號星球沿最快的宇航路徑飛行到 vi 號星球去。顯然,飛船駛過一條航道 是須要時間的,對於航道 j,任意飛船駛過它所花費的時間爲 tj,而且任意兩艘飛船之 間不會產生任何干擾。blog

爲了鼓勵科技創新,L 國國王贊成小 P 的物流公司參與 L 國的航道建設,即容許小 P 把某一條航道改形成蟲洞,飛船駛過蟲洞不消耗時間。get

在蟲洞的建設完成前小 P 的物流公司就預接了 m 個運輸計劃。在蟲洞建設完成後, 這 m 個運輸計劃會同時開始,全部飛船一塊兒出發。當這 m 個運輸計劃都完成時,小 P 的 物流公司的階段性工做就完成了。string

若是小 P 能夠自由選擇將哪一條航道改形成蟲洞,試求出小 P 的物流公司完成階段 性工做所須要的最短期是多少?it

 

$Solution:$

其實挺簡單的……跟保衛王國什麼的無法比……io

題意就是給你幾條樹上路徑,有一次刪除邊權的機會,最小化它們的最大長度。「最大值最小」顯然二分啊。class

考慮怎麼check,首先若是二分出的$ans \ge $最長路徑長度那麼必定是合法的,不過沒什麼用,由於徹底能夠把二分右端點設爲最長路徑長度。

咱們能夠無視長度$\leq ans$的路徑,那麼接下來要作的,就是利用刪除邊權操做在答案中消去最長路徑長度$-ans$這麼大(設爲w)的長度。在剩下的路徑中,若是存在一條這些路徑的公共邊知足邊權$\ge w$,就能夠斷定爲合法的。

求路徑的公共邊能夠轉化爲求樹邊覆蓋次數,樹上差分板子,注意對於邊的差分是x++,y++,lca-=2。

而後路徑長什麼的直接lca求解便可。

因爲它是一道有尊嚴的D2T3,因此確定會防AK。卡一下二分左右邊界能夠苟過去= =。

#include<cstdio>
#include<iostream>
#include<cstring>
#define pa pair<int,int>
#define re register
using namespace std;

const int L=1<<20|1;
char buffer[L],*S,*T;
#define getchar() ((S==T&&(T=(S=buffer)+fread(buffer,1,L,stdin),S==T))?EOF:*S++)

inline int read()
{
    int x=0,f=1;char ch=getchar();
    while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
    while(isdigit(ch))x=x*10+ch-'0',ch=getchar();
    return x*f;
}
const int N=3e5+5;
int n,m,to[N<<1],head[N],nxt[N<<1],tot,w[N<<1];
int size[N],son[N],top[N],fa[N],dep[N],dis[N];
pa p[N];
int D[N],_lca[N],dif[N],maxw;
inline void add(int x,int y,int z)
{
    to[++tot]=y;
    nxt[tot]=head[x];
    head[x]=tot;
    w[tot]=z;
}
void dfs1(int x,int f)
{
    fa[x]=f;dep[x]=dep[f]+1;size[x]=1;
    for(int i=head[x];i;i=nxt[i])
    {
        int y=to[i];
        if(y==f)continue;
        dis[y]=dis[x]+w[i];
        dfs1(y,x);
        size[x]+=size[y];
        if(size[y]>size[son[x]])son[x]=y;
    }
}
void dfs2(int x,int Top)
{
    top[x]=Top;
    if(son[x])dfs2(son[x],Top);
    for(int i=head[x];i;i=nxt[i])
    {
        int y=to[i];
        if(top[y])continue;
        dfs2(y,y);
    }
}
inline int lca(int x,int y)
{
    while(top[x]!=top[y])
    {
        if(dep[top[x]]<dep[top[y]])swap(x,y);
        x=fa[top[x]];
    }
    if(dep[x]>dep[y])swap(x,y);
    return x;
}
void dfs(int x)
{
    for(int i=head[x];i;i=nxt[i])
    {
        int y=to[i];
        if(y==fa[x])continue;
        dfs(y);
        dif[x]+=dif[y];
    }
}
bool judge(int x,int cnt,int len)
{
    for(int i=head[x];i;i=nxt[i])
    {
        int y=to[i];
        if(y==fa[x])continue;
        if(dif[y]==cnt&&w[i]>=len)return 1;
        if(judge(y,cnt,len))return 1;
    }
    return 0;
}

inline bool check(int val)
{
    if(maxw<=val)return 1;
    for(re int i=1;i<=n;i++)dif[i]=0;
    int cnt=0;
    for(re int i=1;i<=m;i++)
    {
        if(D[i]<=val)continue;
        cnt++;
        dif[p[i].first]++;dif[p[i].second]++;
        dif[_lca[i]]-=2;
    }
    dfs(1);
    return judge(1,cnt,maxw-val);
}

int main()
{
    n=read();m=read();
    int maxe=0;
    for(re int i=1;i<n;i++)
    {
        int x=read(),y=read(),z=read();
        add(x,y,z);add(y,x,z);
        maxe=max(maxe,z);
    }
    dfs1(1,0);dfs2(1,1);

    for(re int i=1;i<=m;i++)
    {
        int x=read(),y=read(),LCA=lca(x,y);
        p[i]=make_pair(x,y);
        D[i]=dis[x]+dis[y]-2*dis[LCA];
        maxw=max(maxw,D[i]);
        _lca[i]=LCA;
    }
    int l=maxw-maxe,r=maxw,ans=r;
    while(l<=r)
    {
        int mid=l+r>>1;
        if(check(mid))ans=mid,r=mid-1;
        else l=mid+1;
    }
    printf("%d\n",ans);
    return 0;
}