Luogu P2491 Problem Solving Report

P2491 Fire

Topic description

A country has n cities, any two of these n cities are connected and have a unique path, and the length of each road connecting the two cities is zi (zi<=1000).

People in this country have a cosmic passion for flames, so the most thriving industry in this country is firefighting. Since the government is unbearable for the enthusiasm of the people (a lot of firefighting expenses), but it is helpless (the national approval rate of the presidential election), so it can only try to improve the firefighting capacity.

Now the country's funding is enough to build a fire hub on a path with side length and no more than s (both ends are cities), in order to maximize the utilization of the hub, the maximum distance from all other cities to this path is required to be the smallest. .

You are tasked with overseeing the project, and of course you need to know where the hub should be built.

Input and output format

Input format:

The input contains n lines:

Line 1, two positive integers n and s, separated by a space. where n is the number of cities, and s is the upper bound of the path length. Set the node number as 1, 2, ..., n.

From line 2 to line n, each line gives 3 positive integers separated by spaces, indicating the number and length of the two endpoints of each edge in turn. For example, "2 4 7" means that the length of the side connecting nodes 2 and 4 is 7.

Output format:

The output contains a non-negative integer, that is, the maximum value of all the cities to the selected path, of course, this maximum value must be the smallest among all the schemes.

illustrate

【Data scale and convention】

For 20% of the data, n<=300.

For 50% of the data, n<=3000.

For 100% of the data, n<=300000, and the side length is less than or equal to 1000.


For the site of the construction of the fire station, the choice is optimal in the diameter of the tree.

Diameter of a tree: the longest easy path in a tree

  • Prove:

Suppose the fire station is a yellow chain \(A\) ( \(A\) is not on \(D\) ), in which points \(A_1\) , \(A_2\) ...... \(A_n\) , a certain diameter of the tree is a blue chain \(D\) , and the points on both sides are \(D_1\) , \(D_2\)

Then for the point \(A_i\) , the farthest point in the whole tree is \(D_1\) or \(D_2\)

Proof (Proof in Proof):
Assuming that there is \(S_2\) such that \(D_3\) is the farthest from Ai, then there must be \(S_2+S_1>S_4\) (or \(S_3\) ), that is, The new diameter, not established, is proved.

It can be seen from the above that the distance from the point on the yellow chain to the farthest point outside is
\(Dis=min\{E(A_i,D_1),E(A_i,D_2),i\in[1,n]\} \)

If \(dis\) is the smallest, then the chain \(A\) must be on the chain \(D\) .

However, when \(A\) is on \(D\) , the distance \(f\) from the chain \(A\) to the outside point (ie, the point not on the diameter ) is possibly greater than \(dis\) Yes, it is legal. Is this contradictory?

Not contradictory, because the \(dis\) of any chain \(A\) on the outside is greater than the \(f\) of the chain \(A\) on the diameter

It's not really strict


So we have an idea for this question.

  1. 2 times dfs to find the diameter of the tree (the first time to find a diameter endpoint, the second time to directly extract the diameter)

  2. The longest distance extending outward from each point \(i\) on the preprocessing diameter \(c[i]\)

  3. For the chain to be tested \(A\) , the left end is \(A_i\) , the right end is \(A_j\) , the longest distance at this time is \(max\{E(A_1,A_i),E(A_j, A_n),c[k],k\in[i,j]\}\)

The first two are easy to get, and the prefix sum will do.
The latter is the \(RMQ\) problem, and the \(ST\) table segment tree can be maintained.

But there is a better one, we noticed that we are equivalent to taking a window across the chain \(A\) , yes, proper monotonic queue maintenance.


code:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
#include <queue>
using namespace std;
const int N=300010;
int n,s;
int used[N];
struct node1
{
    int i,w;
    node1(){}
    node1(int i,int w)
    {
        this->i=i;
        this->w=w;
    }
};
deque <node1> q;
struct node
{
    int i,w;
    node(){}
    node(int i,int w)
    {
        this->i=i;
        this->w=w;
    }
};
vector <node > g[N];
int l,m_max=0;
int son[N],ww[N];
int c[N];//节点i外面的最长边
void dfs0(int now,int len)
{
    used[now]=true;
    if(m_max<len)
    {
        m_max=len;
        l=now;
    }
    for(int i=0;i<g[now].size();i++)
    {
        int v=g[now][i].i,w=g[now][i].w;
        if(!used[v])
            dfs0(v,w+len);
    }
}

void dfs1(int now)
{
    used[now]=true;
    for(int i=0;i<g[now].size();i++)
    {
        int v=g[now][i].i,w=g[now][i].w;
        if(!used[v])
        {
            dfs1(v);
            if(ww[v]+w>ww[now])
            {
                ww[now]=ww[v]+w;
                son[now]=v;
            }
        }
    }
}

int dfs(int now)
{
    int mmax=0;
    used[now]=1;
    for(int i=0;i<g[now].size();i++)
    {
        int v=g[now][i].i,w=g[now][i].w;
        if(!used[v])
            mmax=max(dfs(v)+w,mmax);
    }
    return mmax;
}
int a[N],f[N];

int main()
{
    cin>>n>>s;
    int u,v,w;
    for(int i=1;i<n;i++)
    {
        scanf("%d%d%d",&u,&v,&w);
        node tt(v,w);
        g[u].push_back(tt);
        tt.i=u;
        g[v].push_back(tt);
    }
    memset(used,0,sizeof(used));
    dfs0(1,0);//找到左端点
    memset(used,0,sizeof(used));
    memset(son,0,sizeof(son));
    memset(ww,0,sizeof(ww));
    dfs1(l);//存储直径
    memset(used,0,sizeof(used));
    int now=l;
    int cnt=0;
    while(now)
    {
        used[now]=1;
        a[++cnt]=now;
        now=son[now];
    }
    now=l;
    cnt=0;
    while(now)
    {
        c[++cnt]=dfs(now);
        now=son[now];
    }
    for(int i=1;i<=cnt;i++)
        f[i]=ww[a[i]];
    int ans=0x3f3f3f3f,ll=1;
    for(int i=1;i<=cnt;i++)
    {
        node1 tt(i,c[i]);
        while(!q.empty()&&c[i]>q.front().w) q.pop_front();
        q.push_front(tt);
        while(f[ll]-f[i]>s)
        {
            ll++;
            if(q.back().i<ll)
                q.pop_back();
        }
        ans=min(ans,max(f[1]-f[ll],max(f[i],q.back().w)));
    }
    cout<<ans<<endl;
    return 0;
}

in conclusion:

  • Two-pass DFS to find the diameter of the tree
  • The chain that connects the entire tree at the minimum cost with an upper bound is on the diameter of the tree

2018.4.27

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325383673&siteId=291194637