問題の[BZOJ3743] [Coci2015]カンプ溶液

bzoj URLリンク?

質問の意味:

Aが\(N- \)上に、ツリーのノード(K \)\キーポイント、各側を求めて、一定量を必要とする([1、N] \ \ ) 、各開始点から最小重量と値の通る経路バック振り出しにすべてのキーポイントではなく、後。

データ範囲:


50分:\(O(^ N-2)\)

  • 最後に、検討したソースに戻るケースが、その後、それぞれがある行く必要が二回通過する側を、あなたはすべて同じ行くどんなに。すべての側面に行くので、唯一の要件、および減算する最長経路、(マイナス最後のバック離れた)の一定の臨界点への電流源が必要。

  • 最長パスのキーポイントに電流源が良く、頼む(DFS \)\一度だけ。

電流源に示すように、青色ドット、赤ドットキー。

  • いわゆる取る必要がある場合にのみ場合にグラフの粗いエッジは、側面粗いエッジとして、観察することによって求めることができるされている面を、このエッジ接続息子がキーポイントを有するサブツリー

  • だから、各サブツリーたときに、各ソースポイントでキーポイントを見つける\(CNT \)に十分な程度の時間統計を横断します、。時間複雑\(O(N ^ 2) \)

キーコード:

struct cut1{
    int s[2005],dp[2005],mark[2005],suml,mx;
    void dfs(int x,int f,int d){
        if(mark[x]&&d>mx)mx=d;//求最长路径
        if(mark[x])dp[x]=1;
        for(int i=0;i<edge[x].size();i++){
            int y=edge[x][i].to,z=edge[x][i].v;
            if(y==f)continue;
            dfs(y,x,d+z);
            if(dp[y]!=0)suml+=z;//统计所有要走到的边
            dp[x]+=dp[y];
        }
    }
    void solve(){
        for(int i=1,x;i<=k;i++){
            scanf("%d",&x);//输入关键点
            mark[x]=1;
        }
        for(int i=1;i<=n;i++){
            memset(dp,0,sizeof(dp));
            suml=0;mx=0;
            dfs(i,0,0);
            printf("%d\n",suml*2-mx);
        }
    }
}P50;

100:\(O(M)\) 50分から延びるの考えから

そして、50ポイント、2つの大きな問題があります。

  • 各点は、最長経路の特定の臨界点に決定されます

  • 各点は、エッジ(縁、粗)を通って横断するように決定されます

以下のために2番目の質問、問題を解決するには、すでに非常によく説明しました。

で定義されている\(X \)に粗いエッジとルートである(SUM [X]が\)\ \ (Yは\)である\(X \)息子、議論は、次の3つのカテゴリに分けることができます。

具体的な詳細は、コードを参照することができます。


最初の質問については、私は、非常に古典を聞きました私は聞いたことがありません、考え方は、木のDP

パスのサブツリーのその臨界点に注意して、各ノードで最大値時間の長さの値
いったんこれが良く、達成される\(DFSが\)することができます。

注:最大値大臣値は、厳密な意味ではなく、各ノードのために、とその2つの異なる人の息子が入って来ました。それは背後にある特定の理由を説明します。

サブツリーとサブツリーにおけるキーポイントの外側のキー:2つの部分に議論の重要なポイントに私たちは、最長パスポイント。

これとは別に、コードを参照してください。

#include<bits/stdc++.h>
#define debug(a) cout<<#a<<"="<<a<<endl
#define LL long long
using namespace std;
bool cur1;
const LL N=500005,inf=1e9;
struct node{LL to,v;};
vector<node>edge[N];
LL n,K;
LL mx[N][2],mxf[N],cnt[N],sum[N],tmx[N],st[N],top,fa[N],mark[N];
void dfs(LL x,LL f){
    fa[x]=f;mx[x][0]=mx[x][1]=mxf[x]=-inf;
    if(mark[x]){
        mx[x][0]=0;
        cnt[x]=1;
    }
    st[++top]=x;
    for(LL i=0;i<edge[x].size();i++){
        LL y=edge[x][i].to,z=edge[x][i].v;
        if(y==f)continue;
        dfs(y,x);
        cnt[x]+=cnt[y];
        if(cnt[y]){
            sum[1]+=z;
            LL nw=mx[y][0]+z;
            if(nw>=mx[x][0]){
                tmx[x]=y;
                mx[x][1]=mx[x][0];
                mx[x][0]=nw;
            }
            else if(nw>mx[x][1])mx[x][1]=nw;
        }
    }
}
void solve(){
    for(LL i=1;i<=n;i++){
        LL x=st[i];
        for(LL j=0;j<edge[x].size();j++){
            LL y=edge[x][j].to,z=edge[x][j].v;
            if(y==fa[x])continue;
            if(cnt[y]==K)sum[y]=sum[x]-z;
            else if(cnt[y]==0)sum[y]=sum[x]+z;
            else sum[y]=sum[x];
            if(tmx[x]==y)mxf[y]=max(mxf[x],mx[x][1])+z;
            else mxf[y]=max(mxf[x],mx[x][0])+z;
        }
    }
    for(LL i=1;i<=n;i++)
        printf("%lld\n",sum[i]*2-max(mxf[i],mx[i][0]));
}
bool cur2;
int main(){
    scanf("%lld%lld",&n,&K);
    for(LL i=1,x,y,z;i<n;i++){
        scanf("%lld%lld%lld",&x,&y,&z);
        edge[x].push_back(node<%y,z%>);
        edge[y].push_back(node<%x,z%>);
    }
    for(LL i=1,x;i<=K;i++){
        scanf("%lld",&x);
        mark[x]=1;
    }
    dfs(1,0);
    solve();
    return 0;
}

おすすめ

転載: www.cnblogs.com/tangzhiyang/p/11804689.html