Construction of Noip 2018 Day1T3 Track

Keywords: C++

Title Link

problem

Give a tree with edge weight. The weights of a chain are defined as the boundary weights of the chain. It is necessary to select (m) chain and find out the maximum weight of the chain with the smallest weight in (m\).

solution

First of all, there's obviously a dichotomy.

Then consider how to judge whether a dichotomous answer (x) is feasible. That is to say, if we can choose (m) chains, the weight of each chain is greater than or equal to (x\). This is actually greed.

A straight chain is defined as the path from the ancestor of a point to that point.

It can be found that each chain is either a straight chain or a combination of two straight chains at a certain point.

The greedy thing is that for each point, it must be preferred to synthesize straight chains that can be synthesized. Then the maximum length of the straight chain is guaranteed. Because even if the length of the upward transmission is very large, the contribution can only be (1\\\\\\\ So we must first ensure that the most chains are synthesized in the current subtree.

Then the problem becomes getting some straight chain length in a sub-tree. Now merge these straight chains into chains with weights greater than or equal to (x). Then ensure the maximum length of the remaining straight chain.

Here's a dichotomous answer. You can also use a (multiset). Anyway, it's a problem that can be done.

The code is divided into sections, and BF5 is the solution.

code

#include<set>
#include<cstdio>
#include<iostream>
#include<cstdlib>
#include<ctime>
#include<algorithm>
#include<queue>
#include<cstring>
using namespace std;
typedef long long ll;
const int N = 100010;
ll read() {
    ll x = 0,f = 1;char c = getchar();
    while(c < '0' || c > '9') {
        if(c == '-') f = -1;
        c = getchar();
    }
    while(c >= '0' && c <= '9') {
        x = x * 10 + c - '0';
        c = getchar();
    }
    return x * f;
}
int n,m;
struct node {
    int v,nxt,w;
}e[N << 1];
int head[N],ejs;
void add(int u,int v,int w) {
    e[++ejs].v = v;e[ejs].nxt = head[u];head[u] = ejs;e[ejs].w = w;
}
namespace BF1 {
    int dis[N];
    void dfs(int u,int fa) {
        for(int i = head[u];i;i = e[i].nxt) {
            int v = e[i].v;
            if(v == fa) continue;
            dis[v] = dis[u] + e[i].w;
            dfs(v,u);
        }
    }
    void main() {
        dfs(1,0);
        int x = 0;
        for(int i = 1;i <= n;++i) if(dis[i] > dis[x]) x = i;
//      cout<<x<<endl;
        memset(dis,0,sizeof(dis));
        dfs(x,0);
        int ans = 0;
        for(int i = 1;i <= n;++i) ans = max(ans,dis[i]);
        cout<<ans;
    }
}

namespace BF2 {
    int a[N],cnt;
    int check(int x) {
        int p = 1,ret = 0;
        for(int i = cnt;i > p;--i) {
            if(a[i] > x && i > p) {ret++;continue;}
            while(a[p] + a[i] < x && p < i) ++p;
            if(p < i) ret++,p++;
            else break;
        }
        return ret;
    }
    void main() {
        int l = 100000,r = 0;
        for(int i = 1;i <= ejs;i += 2) a[++cnt] = e[i].w,l = min(l,a[cnt]),r += a[cnt];
        sort(a + 1,a + cnt + 1);

        int ans = 0;
        while(l <= r) {
            int mid = (l + r) >> 1;
            if(check(mid) >= m) ans = mid,l = mid + 1;
            else r = mid - 1;
        }
        cout<<ans<<endl;
    }
}
int du[N];
namespace BF3 {
    
    int a[N],cnt;
    void dfs(int u,int fa) {
        for(int i = head[u];i;i = e[i].nxt) {
            int v = e[i].v;
            if(v == fa) continue;
            a[++cnt] = e[i].w;
            dfs(v,u);
        }
    }
    int check(int x) {
        int now = 0,ret = 0;
        for(int i = 1;i <= cnt;++i) {
            now += a[i];
            if(now >= x) now = 0,ret ++;
        }
        return ret;
    }
    void main() {
        for(int i = 1;i <= n;++i) 
            if(du[i] == 1) {dfs(i,0);break;}
        int l = 1000000,r = 0;
        for(int i = 1;i <= ejs;i += 2) {
            l = min(l,e[i].w);r += e[i].w;
        }
        
        int ans = 0;
        while(l <= r) {
            int mid = (l + r) >> 1;
            if(check(mid) >= m) ans = mid,l = mid + 1;
            else r = mid - 1;
        }
        cout<<ans<<endl;
        
    }

}
int L = 100000,R;
namespace BF5 {
    int ANS;
    int dfs(int u,int fa,int x) {
        multiset<int>s;
        int ret = 0;
//      if(!s.empty()) printf("%d\n",u);
        for(int i = head[u];i;i = e[i].nxt) {
            int v = e[i].v;
            if(v == fa) continue;
            int k = dfs(v,u,x);
            if(k + e[i].w >= x) ANS++;
            else s.insert(k + e[i].w);
        }
        while(!s.empty()) {
            multiset<int>::iterator it = s.begin();
            int k = *it;
            s.erase(it);
            multiset<int>::iterator is = s.lower_bound(x - k);
            if(is == s.end()) ret = max(ret,k);
            else ANS++,s.erase(is);
        }
//      s.clear();
        
//      printf("%d %d\n",u,ret);

        return ret;
    }
    void main() {
        int l = L,r = R,ans = 0;
        
        while(l <= r) {

            int mid =(l + r) >> 1;
            ANS = 0;dfs(1,0,mid);
            if(ANS >= m) ans = mid,l = mid + 1;
            else r = mid - 1;
        }
        cout<<ans;
    }
}
int main() {
    n = read(),m = read();
    int bz1 = 1,bz2 = 1;
    for(int i = 1;i < n;++i) {
        int u = read(),v = read(),w = read();
        L = min(L,w);R += w;    
        du[u]++;du[v]++;
    
        add(u,v,w);add(v,u,w);
        if(u != 1) bz1 = 0;
        if(v != u + 1) bz2 = 0;
    }
    
    if(m == 1) {BF1::main();return 0;}
    if(bz1) {BF2::main();return 0;}
    if(bz2) {BF3::main();return 0;}
    BF5::main();
    return 0;
}
/*
7 1
1 2 10
1 3 5
2 4 9
2 5 8
3 6 6
3 7 7
*/

Posted by dungareez on Sun, 29 Sep 2019 07:44:56 -0700