noip2015day2-輸送計画

タイトル説明

$ 2044 $のAD、人類は宇宙の時代に入りました。

\(Lの\)国有\(N \)惑星、そこには\(N-1 \)双方向チャネル、各チャネルは2つの惑星の間に確立されている\(N-1 \)と水路通信\(Lの\)惑星のすべての国インチ

\(P \)物流会社の担当、同社は、フォームごとに、輸送計画を輸送計画の数を持っていますから、物流の宇宙船が必要である\(u_iは\)するために、航空宇宙の惑星の最速ルート番号に沿って飛行\(V_I \)惑星への数。当然、それはチャネルのための時間を要するコース通過宇宙船\は(J \) それにかかる時間の任意の船舶通過\(T_Jの\)および、任意の2つの宇宙船間の干渉を生成しません。

科学技術の革新、奨励するためには\(Lの\を)王は、小さな国に同意した\(P \)に参加するために物流会社を\(Lの\)宇宙船を渡し、ワームホールに変身水路に小さな$のP $を許可する水路の建設州ワームホールは時間がかかるではありません。

小さなワームホールの建設が完了する前に\(P \)物流会社は、事前の受信\(m個\)輸送計画を。ワームホールの建設が完了した後、それ\(m個\)輸送計画はまた、すべての宇宙船で始まる、開始します。その場合には\(m個\)輸送計画が完了したとき、小さな\(P \)物流会社の舞台作品のは完了です。

小さな場合には\(P \)がワームホールに変身し、小さな見つけようとするだろうもちろんのどの自由に選択できます\(P \)物流会社は、完成した作品の舞台のために必要な最小時間はどのくらいですか?

入力

最初の行は2つの正の整数を含む\(N、M \)を表し、\(Lの\)国の数と小遊星\(P \)遊星から企業予備接触輸送計画の数、\(1 \)をします\(N \)番号。

\(N-1 \)構成は、チャネルラインを説明し、前記第一\(Iは\)行三の整数を含む\(a_iを、b_i \)\(T_I \)を表し、\を(私は\)条双方向に建てられたチャネル\(a_iを\)\(b_i \) 2つの惑星の間に、宇宙船はそれがために取ることをいつでも旅\(T_I \)

\(Mの\)行輸送スケジュールが記載されている、第一\(J \)ラインが2つの正の整数を含む(u_j \)\\(v_J \)を表し、\(J \)を輸送計画番目\(u_j \)番惑星に(v_j \)\番号惑星。

データ保証\(1≤u_i、v_i≤n、1 < = N、M <= 300000 \)

データを確認します\(、1≤a_iをb_i≤n\)\(0≤t_i≤1000\)

出力

出力コモン\(1 \)行が含ま\(1 \)の整数を表す小さな\(P \)物流会社は、ステージの作業に必要な最小時間を完了しました。

サンプル入力

6 3 
1 2 3 
1 6 4 
3 1 7 
4 3 6 
3 5 5 
3 6 
2 5 
4 5

サンプル出力

11

まず第一に、思った半分の答えの最大最小値を見るのが自然です。

ああ、2つの点が非常に明白です。

だから、どのように我々はない(\を確認してください)\それを?二点間の経路のための電流より既に小さい(X \)\パスを直接的に無視することができます。

その後、残りのパスが現在よりも大きい\(Xの\)パス、我々は片側のためにこれらを取り除く必要がある経路は、最小最大のすべてのパスです。

つまり、私たちは、パスの交差点最大のエッジを減算する必要があります

唯一のより多くの私たちが食べ残し少なく抑えることができますので、この操作は、非常に明白です。

今、私たちは何をする必要があるすべてのパスの交点を見つけるのですか?

どのようにそれを見つけますか?我々は使用することができ、ツリーの違いを解決するために。

私たちは、その後、どのように我々はそれを変換します、エッジ上のポイントに変換する必要がありますか?

ノードエッジノードは、父と息子のノードに分割されなければならないからです。

息子は片側のみに対応するノードので、私たちは、子ノードの側に移動しました。

パスに添加した場合\(B \) セット\(LCA \)\(B \)\(LCA \) 次いで\(SUM [A] ++、合計[B] ++ 和[LCA] - = 2 \)

我々は現在のノード数と答えた場合\(合計\)は、パスの数は、ノードは、すべてのパスの交点として側面に対応することを示し、条件に満足しません

答えは、更新することができます。

最後に、パス上の最大値を減算する最長パスを見て(<= \)\現在\(X \)であることができます。

データの問題を解決することは大きい。しかし、一般的なアルゴリズムを容易に立ち往生。

だから、我々はいくつかの最適化を必要とします。

1.境界の半分を最適化:

\(L = \)最大右側を減算最長経路長、\(R&LT = \)の最長経路長。

中二分法のような保証回数\(10 \)以下です。

2.再帰を避けてください。

統計的な答えに、私たちは、再帰を解決する必要がある、と再帰は一定であり、

また、ことがわかった唯一のノードとそのサブツリー程度の値、およびサブツリー(DFS \)\子ノードの数が数際の順序でルートノード以上であることを確認してください。

だから、私たちが使用することができます\(DFSを\)シーケンスは後方更新\(合計\)値を。

コードは以下の通りです

#include <bits/stdc++.h>
 
using namespace std;
 
#define LL long long
#define reg register
#define Raed Read
#define debug(x) cerr<<#x<<" = "<<x<<endl;
#define rep(a,b,c) for(reg int a=(b),a##_end_=(c); a<=a##_end_; ++a)
#define ret(a,b,c) for(reg int a=(b),a##_end_=(c); a<a##_end_; ++a)
#define drep(a,b,c) for(reg int a=(b),a##_end_=(c); a>=a##_end_; --a)
#define erep(i,G,x) for(int i=(G).Head[x]; i; i=(G).Nxt[i])
 
inline char G1() {
    static const int LEN=2000005;
    static char U[LEN],*T=U,*E=U;
    if(T==E)T=U,E=U+fread(U,1,LEN,stdin);
    return T==E?EOF:*T++;
}
 
inline int Read(void) {
    int res=0,f=1;
    char c;
    while(c=G1(),c<48||c>57)if(c=='-')f=0;
    do res=(res<<3)+(res<<1)+(c^48);
    while(c=G1(),c>=48&&c<=57);
    return f?res:-res;
}
 
template<class T>inline bool Min(T &a,T const&b) {
    return a>b ?a=b,1:0;
}
template<class T>inline bool Max(T &a,T const&b) {
    return a<b?a=b,1:0;
}
 
const int N=3e5+5,M=3e5+5,mod=1e9+7;
 
bool MOP1;
 
int n,m,A[N],B[N],TT[M];
 
struct Link_list {
    int Tot,Head[N],to[M<<1],Nxt[M<<1],cost[M<<1];
    inline void clear(void) {
        Tot=0;
        memset(Head,0,sizeof Head);
    }
    inline void AddEdgepair(int a,int b,int c) {
        to[++Tot]=b,cost[Tot]=c,Nxt[Tot]=Head[a],Head[a]=Tot;
        to[++Tot]=a,cost[Tot]=c,Nxt[Tot]=Head[b],Head[b]=Tot;
    }
} G;
 
int Fa[M],dep[M],top[M],sz[M],son[M],Dis[M],LCA[N],cnt,Id[N];
 
void dfs1(int x,int f) {
    Id[++cnt]=x;
    dep[x]=dep[f]+1,Fa[x]=f,sz[x]=1;
    erep(i,G,x) {
        int y=G.to[i];
        if(y==f)continue;
        Dis[y]=Dis[x]+G.cost[i];
        TT[y]=G.cost[i];
        dfs1(y,x),sz[x]+=sz[y];
        if(sz[y]>sz[son[x]])son[x]=y;
    }
}
 
void dfs2(int x,int f) {
    top[x]=f;
    if(son[x])dfs2(son[x],f);
    else return;
    erep(i,G,x) {
        int y=G.to[i];
        if(y==Fa[x]||y==son[x])continue;
        dfs2(y,y);
    }
}
 
inline int lca(int x,int y) {
    while(top[x]!=top[y]) {
        if(dep[top[x]]>dep[top[y]])x=Fa[top[x]];
        else y=Fa[top[y]];
    }
    return dep[x]<dep[y]?x:y;
}
 
int res,tot,Sum[N];
 
inline bool check(int x) {
    res=-1,tot=0;
    rep(i,1,n)Sum[i]=0;
    rep(i,1,m) {
        if(Dis[A[i]]+Dis[B[i]]-2*Dis[LCA[i]]<=x)continue;
        tot++,Sum[A[i]]++,Sum[B[i]]++,Sum[LCA[i]]-=2;
    }
    drep(i,n,1) {
        int u=Id[i];
        erep(i,G,u) {
            int y=G.to[i];
            if(y==Fa[u])continue;
            Sum[u]+=Sum[y];
        }
        if(Sum[u]==tot)Max(res,TT[u]);
    }
    if(res==-1)return false;
    rep(i,1,m) {
        if(Dis[A[i]]+Dis[B[i]]-2*Dis[LCA[i]]<=x)continue;
        if(Dis[A[i]]+Dis[B[i]]-2*Dis[LCA[i]]-res>x)return false;
    }
    return true;
}
 
int Ma;
 
inline void solve(void) {
    int L=0,R=0,Ans=0;
    rep(i,1,m)Max(R,Dis[A[i]]+Dis[B[i]]-2*Dis[LCA[i]]);
    L=R-Ma;
    while(L<=R) {
        int mid=(L+R)>>1;
        if(check(mid))Ans=mid,R=mid-1;
        else L=mid+1;
    }
    printf("%d\n",Ans);
}
 
 
bool MOP2;
 
inline void _main(void) {
    n=Read(),m=Read();
    int f=1;
    ret(i,1,n) {
        int a=Read(),b=Read(),c=Read();
        Max(Ma,c),G.AddEdgepair(a,b,c);
    }
    dfs1(1,0),dfs2(1,1);
    rep(i,1,m)A[i]=Read(),B[i]=Read(),LCA[i]=lca(A[i],B[i]);
    solve();
}
 
signed main() {
    _main();
    return 0;
}

おすすめ

転載: www.cnblogs.com/dsjkafdsaf/p/11360357.html