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;
}

浙公网安备 33010602011771号