CF1023F Mobile Phone Network

CF1023F Mobile Phone Network

分析

我们来重新着重分析一下题目要求。

题目需要我们满足下边两个要求:

  • 你的 k 个连接都会被顾客选择。
  • k 个连接的价格总和最大。

我们一个一个来解决

你的k个连接都会被顾客选择

最后形成的是一棵树,则一定生成的是一个最小生成树。

为使我们的k个连接一定被选择,则我们初始时将k条边边权设置为0,直接跑最小生成树。

k个连接的价格总和最大

我们考虑对于一条未在树上的边u->v,对于这条边而言,它的边权一定是要大于等于在树上路径u->v的任意一条边的边权。

则,我们的思路就出来了,我们利用未使用的边,去更新树上路径的所有边的边权最小值

做法如下:

  • 标记m条边中,被选择的边。
  • 接下来枚举,m条边中未被使用的边,去更新树上路径

由于要动态更新,区间最小值。

所以我们考虑使用树剖+线段树

结束啦~~

来看代码

Ac_code

#include<bits/stdc++.h>
using namespace std;
const int N = 5e5 + 10,M = N*2,INF = 0x3f3f3f3f;
struct Node
{
    int l,r,mi,tag;
}tr[N<<2];
struct Edge
{
    int u,v,w;
    bool f;
    bool operator<(const Edge&W) const
    {
        return w<W.w;
    }
}edges[N];
int h[N],ne[M],e[M],w[M],idx;
int sz[N],son[N],fa[N],dep[N],val[N];
int id[N],top[N],nw[N],ts;
int p[N];
int n,k,m;

void add(int a,int b,int c)
{
    e[idx] = b,ne[idx] = h[a],w[idx] = c,h[a] = idx++;
}

int find(int x)
{
    if(p[x]!=x) p[x] = find(p[x]);
    return p[x];
}

void dfs1(int u,int pa,int depth)
{
    sz[u] = 1,dep[u] = depth;
    for(int i=h[u];~i;i=ne[i])
    {
        int j = e[i];
        if(j==pa) continue;
        val[j] = w[i];
        fa[j] = u;
        dfs1(j,u,depth+1);
        sz[u] += sz[j];
        if(sz[j]>sz[son[u]]) son[u] = j;
    }
}

void dfs2(int u,int tp)
{
    top[u] = tp,id[u] = ++ts,nw[ts] = val[u];
    if(!son[u]) return ;
    dfs2(son[u],tp);
    for(int i=h[u];~i;i=ne[i])
    {
        int j = e[i];
        if(j==fa[u]||j==son[u]) continue;
        dfs2(j,j);
    }
}

void build(int u,int l,int r)
{
    if(l==r)
    {
        tr[u] = {l,r,nw[l],INF};
        return ;
    }
    tr[u] = {l,r,0,INF};
    int mid = l + r >> 1;
    build(u<<1,l,mid),build(u<<1|1,mid+1,r);
}

void pushdown(int u)
{
    auto &root = tr[u],&left = tr[u<<1],&right = tr[u<<1|1];
    if(root.tag!=INF)
    {
        left.tag = min(left.tag,root.tag);
        left.mi = min(root.tag,left.mi);
        right.tag = min(right.tag,root.tag);
        right.mi = min(root.tag,right.mi);
        root.tag = INF;
    }
}

void modify(int u,int l,int r,int k)
{
    if(l<=tr[u].l&&tr[u].r<=r)
    {
        tr[u].tag = min(tr[u].tag,k);
        tr[u].mi = min(tr[u].mi,k);
        return ;
    }
    pushdown(u);
    int mid = tr[u].l + tr[u].r >> 1;
    if(l<=mid) modify(u<<1,l,r,k);
    if(r>mid) modify(u<<1|1,l,r,k);
}

int query(int u,int x)
{
    if(tr[u].l==tr[u].r) return tr[u].mi;
    pushdown(u);
    int mid = tr[u].l + tr[u].r >> 1;
    if(x<=mid) return query(u<<1,x);
    else return query(u<<1|1,x);
}

int main()
{
    scanf("%d%d%d",&n,&k,&m);
    for(int i=1;i<=n;i++) p[i] = i,h[i] = -1;
    for(int i=0;i<k;i++)
    {
        int u,v;scanf("%d%d",&u,&v);
        add(u,v,INF),add(v,u,INF);
        int pa = find(u),pb = find(v);
        p[pa] = pb;
    }
    for(int i=0;i<m;i++)
    {
        int u,v,c;scanf("%d%d%d",&u,&v,&c);
        edges[i] = {u,v,c};
    }
    sort(edges,edges+m);
    for(int i=0;i<m;i++)
    {
        int u = edges[i].u,v = edges[i].v,c = edges[i].w;
        int pa = find(u),pb = find(v);
        if(pa!=pb)
        {
            p[pa] = pb;
            add(u,v,0),add(v,u,0);
            edges[i].f = 1;
        }
    }
    dfs1(1,-1,1);
    dfs2(1,1);
    build(1,1,n);
    for(int i=0;i<m;i++)
        if(!edges[i].f)
        {
            int u = edges[i].u,v = edges[i].v,c = edges[i].w;
            while(top[u]!=top[v])
            {
                if(dep[top[u]]<dep[top[v]]) swap(u,v);
                modify(1,id[top[u]],id[u],c);
                u = fa[top[u]];
            }
            if(dep[u]<dep[v]) swap(u,v);
            if(u!=v) modify(1,id[v]+1,id[u],c);
        }
    long long ans = 0;
    for(int i=2;i<=n;i++)
    {
        int res = query(1,id[i]);
        // cout<<res<<endl;
        if(res==INF)
        {
            puts("-1");
            return 0;
        }
        ans += res;
    }
    printf("%lld\n",ans);
    return 0;
}
posted @ 2022-04-30 17:32  艾特玖  阅读(68)  评论(0)    收藏  举报