Submission #267072

#TimeUsernameProblemLanguageResultExecution timeMemory
267072ChrisTMountains and Valleys (CCO20_day1problem3)C++17
25 / 25
3117 ms206452 KiB
#include <bits/stdc++.h>

using namespace std;

template<int K>
struct KMax
{
    pair<int, int> data[K];
    KMax()
    {
        reset();
    }
    void reset()
    {
        for(int i=0; i<K; i++)
            data[i]={-1, 0};
    }
    void insert(int k, int v)
    {
        for(int i=0; i<K; i++) if(data[i].second<v)
        {
            for(int j=K-2; j>=i; j--)
                data[j+1]=data[j];
            data[i]={k, v};
            break;
        }
    }
    int get(int ban, int k)
    {
        int ret=0;
        for(int i=0; i<K; i++) if(data[i].first!=ban)
        {
            ret+=data[i].second;
            if(--k==0)
                break;
        }
        return ret;
    }
    int get(int ban1, int ban2, int k)
    {
        int ret=0;
        for(int i=0; i<K; i++) if(data[i].first!=ban1 && data[i].first!=ban2)
        {
            ret+=data[i].second;
            if(--k==0)
                break;
        }
        return ret;
    }
};

struct edge
{
    int u, v, w;
};

int N;
vector<vector<int>> adj;
vector<edge> q, qb;
vector<int> qc;
vector<int> sz;
vector<int> depth;
vector<int> tin;
vector<int> invt;
int tnow;
vector<int> subtree;
vector<int> lpath; // longest path in this subtree
vector<int> lerased; // longest path from an erased subtree next to this, includes erased edge
vector<int> leraseddiam; // longest diameter from an erased subtree next to this
vector<int> ldiam; // longest diameter in this subtree
// type 0
//  . (. .) (c)
// (.)
// /|
vector<int > type0; // longest path off the main path
// type 1
// (- -) - (. .) . (c)
//       |
vector<int> type1;

void dfs_type012(int u, int p, int max_t0, int max_t1, int max_p2, int max_t2)
{
    type0[u]=max(max_t0, ldiam[u]);
    type1[u]=max(max_t1, lpath[u]);
    KMax<2> m2d;
    for(auto& v: adj[u]) if(v!=p)
        m2d.insert(v, ldiam[v]);
    KMax<3> m3;
    m3.insert(u, lerased[u]);
    for(auto& v: adj[u]) if(v!=p)
        m3.insert(v, lpath[v]+1);
    for(auto& v: adj[u]) if(v!=p)
    {
        int w=m3.get(v, 1);
        dfs_type012(v, u, max(max_t0, max(m2d.get(v, 1), m3.get(v, 2))),
                          max(max_t1, w)+1,
                          max(max_p2, w+depth[u]), max(max_t2, w+max_p2)+1);
    }
}

pair<int, int> dfs(int u, int p)
{
    pair<int, int> ret={u, 0};
    for(auto& v: adj[u]) if(v!=p)
    {
        int a, b;
        tie(a, b)=dfs(v, u);
        if(b+1>ret.second)
            ret={a, b+1};
    }
    return ret;
}

void dfs_sz(int u, int p)
{
    sz[u]=1;
    for(auto& v: adj[u]) if(v!=p)
    {
        dfs_sz(v, u);
        sz[u]+=sz[v];
    }
}

void dfs_t(int u, int p)
{
    tin[u]=tnow++;
    invt[tin[u]]=u;
    lpath[u]=lerased[u];
    ldiam[u]=leraseddiam[u];
    for(auto& v: adj[u]) if(v!=p)
    {
        depth[v]=depth[u]+1;
        dfs_t(v, u);
        lpath[u]=max(lpath[u], lpath[v]+1);
        ldiam[u]=max(ldiam[u], ldiam[v]);
    }
    KMax<2> m2;
    m2.insert(u, lerased[u]);
    for(auto& v: adj[u]) if(v!=p)
        m2.insert(v, lpath[v]+1);
    ldiam[u]=max(ldiam[u], m2.data[0].second+m2.data[1].second);
}

int get_centroid(int u)
{
    while(1)
    {
        int w=-1;
        for(auto& v: adj[u]) if(w==-1 || sz[v]>sz[w])
            w=v;
        if(w==-1 || sz[w]*2<=sz[u])
            break;
        sz[u]-=sz[w];
        sz[w]+=sz[u];
        u=w;
    }
    return u;
}

int solve(int u, int ql, int qr)
{
    if(ql==qr)
        return 0x3f3f3f3f;
    dfs_sz(u, u);
    u=get_centroid(u);
    tnow=0;
    depth[u]=0;
    dfs_t(u, u);
    int last=tin[u], lastu=u;
    for(auto& v: adj[u])
    {
        for(int i=last; i<tin[v]; i++)
            subtree[invt[i]]=lastu;
        last=tin[v];
        lastu=v;
    }
    for(int i=last; i<tnow; i++)
        subtree[invt[i]]=lastu;
    type0[u]=type1[u]=0;
    KMax<3> m3;
    KMax<4> m4;
    m4.insert(-1, lerased[u]);
    for(auto& v: adj[u])
    {
        qc[v]=0;
        m3.insert(v, ldiam[v]);
        m4.insert(v, lpath[v]+1);
        dfs_type012(v, u, 0, 0, 0, 0);
    }
    int qo=ql, qp=ql;
    int ret=0x3f3f3f3f;
    for(; ql<qr; ql++)
    {
        if(subtree[q[ql].u]==subtree[q[ql].v])
        {
            qc[subtree[q[ql].u]]++;
            q[qp++]=q[ql];
            continue;
        }
        int u=q[ql].u, v=q[ql].v, w=q[ql].w;
        // 3 cases:
        // 1. full cycle
        ret=min(ret, 2*(N-1+w)-depth[u]-depth[v]-w-max(max(type0[u], type0[v]), max(m3.get(subtree[u], subtree[v], 1), m4.get(subtree[u], subtree[v], 2))));
        // 2. partial cycle (gap on different sides)
        ret=min(ret, 2*(N-2+w)-w-type1[u]-type1[v]);
        // 3. partial cycle (gap on same side)
        // 3c. on u's side, v's end on centroid
        ret=min(ret, 2*(N-2+w)-w-type1[u]-depth[v]-m4.get(subtree[u], subtree[v], 1));
        // 3d. on v's side, u's end on centroid
        ret=min(ret, 2*(N-2+w)-w-type1[v]-depth[u]-m4.get(subtree[u], subtree[v], 1));
    }
    int qcs=0;
    for(auto& v: adj[u])
    {
        qcs+=qc[v];
        qc[v]=qcs;
    }
    for(int i=qo; i<qp; i++)
        qb[--qc[subtree[q[i].u]]]=q[i];
    for(int i=qo; i<qp; i++)
        q[i]=qb[i-qo];
    vector<pair<int, int>> ival;
    int l=qo, r;
    for(auto& v: adj[u])
    {
        adj[v].erase(find(adj[v].begin(), adj[v].end(), u));
        lerased[v]=max(lerased[v], m4.get(v, 1)+1);
        leraseddiam[v]=max(leraseddiam[v], max(lerased[v], max(m3.get(v, 1), m4.get(v, 2))));
        for(r=l; r<qp && subtree[q[r].u]==v; r++);
        ival.push_back({l, r});
        l=r;
    }
    for(int i=0; i<(int)adj[u].size(); i++)
        ret=min(ret, solve(adj[u][i], ival[i].first, ival[i].second));
    return ret;
}

int min_walk(int n, std::vector<int> x, std::vector<int> y, std::vector<int> w)
{
    N=n;
    int m=x.size();
    adj.resize(n);
    for(int i=0; i<m; i++) if(w[i]==1)
    {
        adj[x[i]].push_back(y[i]);
        adj[y[i]].push_back(x[i]);
    }
    int ans=2*(n-1)-dfs(dfs(0, 0).first, -1).second;
    for(int i=0; i<m; i++) if(w[i]>1 && x[i]!=y[i])
        q.push_back({x[i], y[i], w[i]});
    qb.resize(q.size());
    qc.resize(n);
    sz.resize(n);
    depth.resize(n);
    tin.resize(n);
    invt.resize(n);
    subtree.resize(n);
    lpath.resize(n);
    lerased.resize(n);
    leraseddiam.resize(n);
    ldiam.resize(n);
    type0.resize(n);
    type1.resize(n);
    ans=min(ans, solve(0, 0, (int)q.size()));
    return ans;
}

int main()
{
    int n, m;
    ignore = scanf("%d%d", &n, &m);
    std::vector<int> x(m), y(m), w(m);
    for(int i=0; i<m; i++)
        ignore = scanf("%d%d%d", &x[i], &y[i], &w[i]);
    printf("%d\n", min_walk(n, x, y, w));
    return 0;
}
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...