AtCoder AGC007Eジンシクと旅行(二点、DP、ヒューリスティックマージ)

トピックリンク

https://atcoder.jp/contests/agc007/tasks/agc007_e

問題の解決策

まず、非常にシンプルなアイデアは半分の回答があるさ\(中旬\)実現可能性DPを使用して、設定\(DP [U] [X ] [Y]は\) を表す\(uと\)あなたはのサブツリーを見つけることができるかどうかフロントからの最初の葉がされた後のパスは、(X-を\)\葉前の最後の1離れた後、\(y軸の\)
我々は完全に真の状態のみを記録することができます見つけるなどのDPは明らかに、有用な作業の多くを行って(\ (X、Y)\) さらに法的な状態の場合に見出される\((X、Y)\ ) 別の法的な状態が存在する\((X 'Y' )\) を満たすが、\(X '\ル、X、 Y' < \ Y-LE \)は、その後、格納する必要がない\ \((x、y)を ) 。だから我々は、押し\(X \) ストレージの増加のために、\((X、Y)\) そう\(のy \)を減少する必要があります。
この単純化した後、我々は魔法の自然が見つかりました:みましょう\(S_U \)をする(\ uと)\レコードのコレクション、\(私は\)\(jは\)その後、彼の息子のために、| S_U | \(\ルを2 \分(| S_I |、| S_j |)\)ためです\(X \)\(のy \)の値が自分の持っている(| S_I | \分(\ 、| S_j |)\) 種。
仮定パスの始まりを:マージのプロセスを考えてみましょう(私は\)\そして、私たちが見つける必要があり、内部(S_j \でS_Iで(X_1、Y_1)\、(X_2、Y_2)\)\場合は、\(Y_1 + V_I + + X_2 v_J \ルMID \) 置く((X_1 + V_I、Y_2 \を + w_j)\) を添加した\(S_U \を)これは二重のポインタの最適化により明らかであろう。。このパスはから始まる\ \)(Jは上にもあります共感。
ヒューリスティック分析は同様の複雑さをマージすることができます。トータルカウント複雑さの半分\(O(N \ログ^ 2N)\)

コード

#include<cstdio>
#include<cstdlib>
#include<iostream>
#include<cassert>
#include<vector>
#define llong long long
#define pll pair<llong,llong>
#define mkpr make_pair
using namespace std;

const int N = 1<<17;
int son[N+3][2];
llong w[N+3];
vector<pll> dp[N+3];
vector<pll> aux1,aux2;
int n,en;
llong mid;

void dfs(int u)
{
//  printf("dfs %d\n",u);
    dp[u].clear(); int ls = son[u][0],rs = son[u][1];
    if(!ls)
    {
        dp[u].push_back(mkpr(0ll,0ll));
        return;
    }
    dfs(ls); dfs(rs);
    aux1.clear(); aux2.clear();
    if(dp[rs].size())
    {
        int j = 0;
        for(int i=0; i<dp[ls].size(); i++)
        {
            while(j<dp[rs].size()-1 && dp[rs][j+1].first+dp[ls][i].second+w[ls]+w[rs]<=mid) {j++;}
            if(j<dp[rs].size() && dp[rs][j].first+dp[ls][i].second+w[ls]+w[rs]<=mid) {aux1.push_back(mkpr(dp[ls][i].first+w[ls],dp[rs][j].second+w[rs]));}
        }
    }
    if(dp[ls].size())
    {
        int j = 0;
        for(int i=0; i<dp[rs].size(); i++)
        {
            while(j<dp[ls].size()-1 && dp[ls][j+1].first+dp[rs][i].second+w[ls]+w[rs]<=mid) {j++;}
            if(j<dp[ls].size() && dp[ls][j].first+dp[rs][i].second+w[ls]+w[rs]<=mid) {aux2.push_back(mkpr(dp[rs][i].first+w[rs],dp[ls][j].second+w[ls]));}
        }
    }
    int j = 0,k = 0; llong cur = 1ll<<34;
    while(j<aux1.size() || k<aux2.size())
    {
        if(k==aux2.size() || (j<aux1.size() && aux1[j].first<=aux2[k].first))
        {
            if(aux1[j].second<cur) {dp[u].push_back(aux1[j]); cur = aux1[j].second;}
            j++;
        }
        else
        {
            if(aux2[k].second<cur) {dp[u].push_back(aux2[k]); cur = aux2[k].second;}
            k++;
        }
    }
}

bool check()
{
    dfs(1);
    if(dp[1].size()) {return true;}
    else {return false;}
}

int main()
{
    scanf("%d",&n);
    for(int i=2; i<=n; i++)
    {
        int u; llong x; scanf("%d%lld",&u,&x);
        w[i] = x; if(son[u][0]) son[u][1] = i; else son[u][0] = i;
    }
    llong left = 0ll,right = 1ll<<34;
    while(left<right)
    {
        mid = left+((right-left)>>1)
//      printf("mid=%lld\n",mid);
        bool ok = check();
        if(ok) {right = mid;}
        else {left = mid+1;}
    }
    printf("%lld\n",right);
    return 0;
}

おすすめ

転載: www.cnblogs.com/suncongbo/p/11527315.html
おすすめ