Codeforces Round #495 (Div. 2) E. Sonya and Ice Cream 树形DP 找树直径

E. Sonya and Ice Cream
time limit per test2 seconds
memory limit per test256 megabytes
inputstandard input
outputstandard output
Sonya likes ice cream very much. She eats it even during programming competitions. That is why the girl decided that she wants to open her own ice cream shops.

Sonya lives in a city with
n
junctions and
n

1
streets between them. All streets are two-way and connect two junctions. It is possible to travel from any junction to any other using one or more streets. City Hall allows opening shops only on junctions. The girl cannot open shops in the middle of streets.

Sonya has exactly
k
friends whom she can trust. If she opens a shop, one of her friends has to work there and not to allow anybody to eat an ice cream not paying for it. Since Sonya does not want to skip an important competition, she will not work in shops personally.

Sonya wants all her ice cream shops to form a simple path of the length
r
(
1

r

k
), i.e. to be located in different junctions
f
1
,
f
2
,

,
f
r
and there is street between
f
i
and
f
i
+
1
for each
i
from
1
to
r

1
.

The girl takes care of potential buyers, so she also wants to minimize the maximum distance between the junctions to the nearest ice cream shop. The distance between two junctions
a
and
b
is equal to the sum of all the street lengths that you need to pass to get from the junction
a
to the junction
b
. So Sonya wants to minimize

max
a

min
1

i

r

d
a
,
f
i
where
a
takes a value of all possible
n
junctions,
f
i
— the junction where the
i
-th Sonya’s shop is located, and
d
x
,
y
— the distance between the junctions
x
and
y
.

Sonya is not sure that she can find the optimal shops locations, that is why she is asking you to help her to open not more than
k
shops that will form a simple path and the maximum distance between any junction and the nearest shop would be minimal.

Input
The first line contains two integers
n
and
k
(
1

k

n

10
5
) — the number of junctions and friends respectively.

Each of the next
n

1
lines contains three integers
u
i
,
v
i
, and
d
i
(
1

u
i
,
v
i

n
,
v
i

u
i
,
1

d

10
4
) — junctions that are connected by a street and the length of this street. It is guaranteed that each pair of junctions is connected by at most one street. It is guaranteed that you can get from any junctions to any other.

Output
Print one number — the minimal possible maximum distance that you need to pass to get from any junction to the nearest ice cream shop. Sonya’s shops must form a simple path and the number of shops must be at most
k
.

Examples
inputCopy
6 2
1 2 3
2 3 4
4 5 2
4 6 3
2 4 6
outputCopy
4
inputCopy
10 3
1 2 5
5 7 2
3 2 6
10 6 3
3 8 1
6 4 2
4 1 6
6 9 4
5 2 5
outputCopy
7

题意 给出一棵树的描述和一个k 有你在树上求出一条简单路径, 使得不在简单路径上的的点走到简单路径上的花费的最大值最小。要你求出这个最小花费。

解题思路:
首先考虑k足够大的情况, 这个时候 我们肯定是找一条树上最长链 也就是树直径。
然后就能很轻松的推广到k不够大的情况。 能够很轻松的想到,我们只要贪心得删除最长链的上端点,直到剩下的链的长度小于等于k即可。
找最长链是一个经典树上DP可以O(n)的求出, 贪心删点也是O(n)的 总复杂度 O(n)
我写的有点复杂 其实可以写得很简洁。。

#include <string>
#include<string.h>
#include<vector>
#include<queue>
#include<cmath>
#include<algorithm>
#include<map>
#include<set>
#include<cstdio>
#include<iostream>
using namespace std;
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define fuck(x) cout<<x<<endl
#define mem(a,b) memset(a,b,sizeof a)
const int MAX=1e5+5;
class e {
public:
    int u,v,next,w;
};
int head[MAX];
e edge[MAX<<1];
int tot=0;
void add(int u,int v,int w) {
    edge[tot].w=w;
    edge[tot].u=u;
    edge[tot].v=v;
    edge[tot].next=head[u];
    head[u]=tot;
    tot++;
}
void init() {
    mem(head,-1);
    tot=0;
}
int maxid[MAX],smaxid[MAX];// 最长链下一节点id,次长链下一节点id
int maxs[MAX],smaxs[MAX];// 最长链 次长链
void myp(int u) {
    fuck(u);
    fuck(smaxid[u]);
}
void dfs1(int u,int per) { // 由儿子节点状态更新父节点
    //cout<<u<<endl;
    for(int i=head[u]; i!=-1; i=edge[i].next) {
        int v=edge[i].v,w=edge[i].w;
        if(v==per)
            continue;
        dfs1(v,u);
        if(maxs[u]<maxs[v]+w) {
            smaxid[u]=maxid[u];
            smaxs[u]=maxs[u];
            maxid[u]=v;
            maxs[u]=maxs[v]+w;
        } else if(smaxs[u]<maxs[v]+w) {
            smaxid[u]=v;
            smaxs[u]=maxs[v]+w;
        }
        //myp(u);myp(v);
    }
}
void dfs2(int u,int per) { //由父亲节点状态更新儿子节点
    //cout<<u<<endl;
    for(int i=head[u]; i!=-1; i=edge[i].next) {

        int v=edge[i].v;
        if(v==per)
            continue;
        if(maxid[u]==v) {
            if(smaxs[u]+edge[i].w>smaxs[v]) {
                smaxs[v]=smaxs[u]+edge[i].w;
                smaxid[v]=u;
            }
        } else {
            if(maxs[u]+edge[i].w>smaxs[v]) {
                smaxs[v]=maxs[u]+edge[i].w;
                smaxid[v]=u;
            }
        }
        if(smaxs[v]>maxs[v]) {
            swap(smaxid[v],maxid[v]);
            swap(smaxs[v],maxs[v]);
        }
        dfs2(v,u);
    }
}
int son[MAX],fa[MAX];
int wson[MAX],wfa[MAX];
int len[MAX];
void dfs3(int u,int pre) {
    if(u==0) return;
    if(maxid[u]!=pre) {
        son[u]=maxid[u];
        fa[maxid[u]]=u;
    } else {
        son[u]=smaxid[u];
        fa[smaxid[u]]=u;
    }
    for(int i=head[u]; i!=-1; i=edge[i].next) {
        int v=edge[i].v;
        if(v==son[u]){
            wson[u]=edge[i].w;
            continue;
        }
        if(v==fa[u]){
            wfa[u]=edge[i].w;
            continue;
        }
        len[u]=max(len[u],smaxs[v]+edge[i].w);
    }
    printf("len[%d]=%d\n",u,len[u]);
    dfs3(son[u],u);
}
int main() {
    int n,k;
    int u,v;
    while(~scanf("%d%d",&n,&k)) {
        mem(maxid,0);
        mem(smaxid,0);
        mem(maxs,0);
        mem(smaxs,0);
        init();
        for(int i=1; i<n; i++) {
            int len;
            scanf("%d %d %d",&u,&v,&len);
            add(u,v,len);
            add(v,u,len);
        }
        dfs1(1,-1);
        dfs2(1,-1);
        int nmax=0,nid=1;
        for(int i=1; i<=n; i++) {
            //cout<<maxs[i]<<endl;
            if(nmax<maxs[i]) {
                nmax=maxs[i];
                nid=i;
            }
        }
        dfs3(nid,-1);
        int l=nid,r=nid;
        int lens=1;
        while(son[r]){
            r=son[r];
            lens++;
        }
        cout<<l<<","<<r<<endl;
        while(lens>k){
            if(wson[l]+len[l]<wfa[r]+len[r]){
                int pre=l;
                l=son[l];
                len[l]=max(len[l],wson[pre]+len[pre]);
                printf("len[%d]=%d\n",l,len[l]);

            }else{
                int pre=r;
                r=fa[r];
                len[r]=max(len[r],wfa[pre]+len[pre]);
                printf("len[%d]=%d\n",r,len[r]);
            }
            cout<<l<<","<<r<<endl;
            lens--;
        }
        int ans=0;
        for(int i=l;;i=son[i]){
            ans=max(ans,len[i]);
            if(i==r) break;
            //cout<<i<<endl;
        }
        cout<<ans<<endl;
    }
}

猜你喜欢

转载自blog.csdn.net/lifelikes/article/details/81195926