6364. [2019年9月20日]馬のシミュレーションNOIP2019

タイトル説明




問題の解決策

一種明確な水方法:MAX(0、 - (右ドット - 右サイド及び* 2))

それは小さくてもよい物理的な価値の途中でハングアップしますので、そうしようと検討し、少なくとも物理的な値に必要なサブツリーそれらのそれぞれを終了します


サブツリーから現在のポイントの答えを問い合わせます

Meikeは、サブツリーを設定するまでのルートから離れ合計への貢献を通過し、必要な物理値f

現在のポイントを追加するために - >息子、このエッジなので、実際に* 2の貢献和「= sum-右側を終えます

所望の物理値f「= MAX(エッジ重み+ F、2 *右側-sum)、実際には、2例場所があります

①現在のポイント - >息子 - >サブツリー( - >息子)、それは最悪の場合(最悪のサブツリー+右側)であります

②現在のポイント - >息子 - >サブツリー - >息子 - >現在のポイント、最終的な貢献は、実際に* 2の右側をsum-、あなたは少なくともmax(0、* 2和右側)が必要ですの物理的


もちろん、大小規模のニーズに応じて、ポイントの貢献≥0のために取ります

貢献<0点、低減量=の定義 - 寄与

まあ、需要に応じて-の量削減降順の並べ替えをすることができます

証明:

定義の違い=需要 - 削減量

二人の息子、その差の量を減少させるための第二CD用、それぞれ第一の息子およびB、のために提供され

差に応じてソートされていると仮定し、隣接する2人の息子を注文した後、そこa≥c

交換は、より良いことを証明しません後

xは途中でいない負の数と需要を達成できることを保証するために、これら2つの物理サブツリーの前に行ってみよう

そして、そこに

交換前:

x≥a+ B、xb≥c+ D

交換後:

x≥c+ D、xd≥a+ B

式によれば

+物理的回復のルートへの貢献-のみMeikeサブツリーと残留強度の量を減らす=、体力を回復するには、 =変数なので、残りは少なく、物理的に小さく答えで見つけることができます

交換前と後の残存強度がそうするために、XBDあるので、可能な限り小さくXを作る(あまりにも多くが黒字につながる可能性があります)

彼らは証拠になりました

MAX(A + B、B + C + D)≤max(C + D、A + B + D)

+ B +d≤max(C + D、A + B + D)、およびA + B +d≥a+ BとB + C + D(a≥c)ので、そのようMAX(A + B、B + C + D)≤a+ B +d≤max(C + D、A + B + D)

証明されました

コード

#include <algorithm>
#include <iostream>
#include <cstdlib>
#include <cstring>
#include <cstdio>
#define fo(a,b,c) for (a=b; a<=c; a++)
#define fd(a,b,c) for (a=b; a>=c; a--)
#define min(a,b) (a<b?a:b)
#define max(a,b) (a>b?a:b)
using namespace std;

struct type{
    long long f,sum;
} b[100001],c[100001];
int a[200001][3];
int ls[100001];
int w[100001];
long long f[100001];
long long sum[100001];
int n,i,j,k,l,len;
long long ans;

bool cmp(type a,type b)
{
    return a.f<b.f;
}
bool Cmp(type a,type b)
{
    return a.f-a.sum>b.f-b.sum;
}

void New(int x,int y,int z)
{
    ++len;
    a[len][0]=y;
    a[len][1]=ls[x];
    a[len][2]=z;
    ls[x]=len;
}

void dfs(int Fa,int t)
{
    int i,l1=0,l2=0;
    long long now=w[t];
    
    sum[t]=w[t];
    
    for (i=ls[t]; i; i=a[i][1])
    if (a[i][0]!=Fa)
    {
        dfs(t,a[i][0]);
        sum[t]+=sum[a[i][0]]-a[i][2]-a[i][2];
    }
    
    if (!ls[t]) return;
    
    for (i=ls[t]; i; i=a[i][1])
    if (a[i][0]!=Fa)
    {
        if (sum[a[i][0]]-a[i][2]-a[i][2]>=0)
        {
            ++l1;
            b[l1].f=max(f[a[i][0]]+a[i][2],-(sum[a[i][0]]-a[i][2]-a[i][2]));
            b[l1].sum=sum[a[i][0]]-a[i][2]-a[i][2];
        }
        else
        {
            ++l2;
            c[l2].f=max(f[a[i][0]]+a[i][2],-(sum[a[i][0]]-a[i][2]-a[i][2]));
            c[l2].sum=-(sum[a[i][0]]-a[i][2]-a[i][2]);
        }
    }
    
    if (l1)
    {
        sort(b+1,b+l1+1,cmp);
        fo(i,1,l1)
        {
            if (now<b[i].f)
            {
                f[t]+=b[i].f-now;
                now=b[i].f;
            }
            now+=b[i].sum;
        }
    }
    if (l2)
    {
        sort(c+1,c+l2+1,Cmp);
        if (now<(c[1].f-c[1].sum))
        {
            f[t]+=(c[1].f-c[1].sum)-now;
            now=0;
        }
        else
        now-=(c[1].f-c[1].sum);
        
        fo(i,1,l2)
        {
            if (i>1)
            now+=(c[i-1].f-c[i-1].sum)-(c[i].f-c[i].sum);
            
            if (now<c[i].sum)
            {
                f[t]+=c[i].sum-now;
                now=c[i].sum;
            }
            now-=c[i].sum;
        }
    }
}

int main()
{
//  freopen("a.in","r",stdin);
//  freopen("b.out","w",stdout);
    freopen("horse.in","r",stdin);
    freopen("horse.out","w",stdout);
    
    scanf("%d",&n);
    fo(i,1,n)
    scanf("%d",&w[i]);
    fo(i,2,n)
    {
        scanf("%d%d%d",&j,&k,&l);
        
        New(j,k,l);
        New(k,j,l);
    }
    
    dfs(0,1);
    
    printf("%lld\n",f[1]);
    
    fclose(stdin);
    fclose(stdout);
    
    return 0;
}

おすすめ

転載: www.cnblogs.com/gmh77/p/11567372.html