• [CF1023F] Mobile Phone Network


    题目大意

    网络有 (n) 个节点。
    你的竞争者在一些节点之间提供了连接。竞争者提供了 (m) 个连接,对于提供的第 (i) 个连接,联通了 (fa_i)​ 和 (fb_i) ,价格为 (fw_i)​ 。
    你想提供 (k) 个连接。(保证这些连接不成环。)第 (j) 个连接联通了 (ga_j)​ 和 (gb_j)​ ,它们的价格还没有决定。
    你想设置合适的价格,使得:

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

    所有连接都是双向的。
    输出这个最大值。如果最大值无穷大,输出 (-1)

    解析

    如果k个链接都要被客户选择,那么这k条边都要在最小生成树上。所以,不妨先强制这k条边在最小生成树上,如果(kleq n-1)就再从(m)条已知边中从小到大加入直至构造出最小生成树。接下来考虑剩下的边。由于要保证一定不在最小生成树上,那么对于这样一条边((u,v)),最小生成树上(u)(v)的路径上的每一条边都要小于或等于((u,v))的边权。可以用树链剖分维护链上最小值来实现。

    代码

    #include <iostream>
    #include <cstdio>
    #include <algorithm>
    #define int long long
    #define N 500002
    using namespace std;
    const int inf=1<<30;
    struct SegmentTree{
    	int dat,add;
    }t[N*4];
    struct Edge{
    	int u,v,w;
    }e[N];
    int head[N],ver[N*2],nxt[N*2],edge[N*2],w[N],l;
    int n,m,k,i,fa[N],size[N],son[N],dep[N],top[N],pos[N],in[N],tim;
    bool vis[N];
    int read()
    {
    	char c=getchar();
    	int w=0;
    	while(c<'0'||c>'9') c=getchar();
    	while(c<='9'&&c>='0'){
    		w=w*10+c-'0';
    		c=getchar();
    	}
    	return w;
    }
    void insert(int x,int y,int z)
    {
    	l++;
    	ver[l]=y;
    	edge[l]=z;
    	nxt[l]=head[x];
    	head[x]=l;
    }
    int find(int x)
    {
    	if(fa[x]!=x) fa[x]=find(fa[x]);
    	return fa[x];
    }
    int my_comp(const Edge &x,const Edge &y)
    {
    	return x.w<y.w;
    }
    void Kruskal()
    {
    	int cnt=n-k;
    	sort(e+1,e+m+1,my_comp);
    	for(int i=1;i<=m;i++){
    		if(cnt==1) break;
    		int f1=find(e[i].u),f2=find(e[i].v);
    		if(f1!=f2){
    			fa[f1]=f2;
    			insert(e[i].u,e[i].v,e[i].w);
    			insert(e[i].v,e[i].u,e[i].w);
    			vis[i]=1;
    			cnt--;
    		}
    	}
    }
    void dfs1(int x,int pre)
    {
    	fa[x]=pre;
    	dep[x]=dep[pre]+1;
    	size[x]=1;
    	for(int i=head[x];i;i=nxt[i]){
    		int y=ver[i];
    		if(y!=pre){
    			w[y]=edge[i];
    			dfs1(y,x);
    			size[x]+=size[y];
    			if(size[y]>size[son[x]]) son[x]=y;
    		}
    	}
    }
    void dfs2(int x,int t)
    {
    	top[x]=t;
    	in[x]=++tim;
    	pos[tim]=x;
    	if(son[x]) dfs2(son[x],t);
    	for(int i=head[x];i;i=nxt[i]){
    		int y=ver[i];
    		if(y!=fa[x]&&y!=son[x]) dfs2(y,y);
    	}
    }
    void update(int p)
    {
    	t[p].dat=max(t[p*2].dat,t[p*2+1].dat);
    }
    void spread(int p)
    {
    	if(t[p].add){
    		if(t[p].add<t[p*2].dat) t[p*2].dat=t[p*2].add=t[p].add;
    		if(t[p].add<t[p*2+1].dat) t[p*2+1].dat=t[p*2+1].add=t[p].add;
    		t[p].add=0;
    	}
    }
    void build(int p,int l,int r)
    {
    	if(l==r){
    		t[p].dat=w[pos[l]];
    		return;
    	}
    	int mid=(l+r)/2;
    	build(p*2,l,mid);
    	build(p*2+1,mid+1,r);
    	update(p);
    }
    void change(int p,int l,int r,int ql,int qr,int x)
    {
    	if(ql<=l&&r<=qr){
    		if(x<t[p].dat) t[p].dat=t[p].add=x;
    		return;
    	}
    	int mid=(l+r)/2;
    	spread(p);
    	if(ql<=mid) change(p*2,l,mid,ql,qr,x);
    	if(qr>mid) change(p*2+1,mid+1,r,ql,qr,x);
    }
    int ask(int p,int l,int r,int x)
    {
    	if(l==r) return t[p].dat;
    	int mid=(l+r)/2;
    	spread(p);
    	if(x<=mid) return ask(p*2,l,mid,x);
    	return ask(p*2+1,mid+1,r,x);
    }
    void Change(int u,int v,int w)
    {
    	while(top[u]!=top[v]){
    		if(dep[top[u]]<dep[top[v]]) swap(u,v);
    		change(1,1,n,in[top[u]],in[u],w);
    		u=fa[top[u]];
    	}
    	if(u==v) return;
    	if(dep[u]>dep[v]) swap(u,v);
    	change(1,1,n,in[u]+1,in[v],w);
    }
    signed main()
    {
    	n=read();k=read();m=read();
    	for(i=1;i<=n;i++) fa[i]=i;
    	for(i=1;i<=k;i++){
    		int u=read(),v=read();
    		insert(u,v,inf);
    		insert(v,u,inf);
    		fa[find(u)]=find(v);
    	}
    	for(i=1;i<=m;i++) e[i].u=read(),e[i].v=read(),e[i].w=read();
    	Kruskal();
    	dfs1(1,0);dfs2(1,1);
    	build(1,1,n);
    	for(i=1;i<=m;i++){
    		if(!vis[i]) Change(e[i].u,e[i].v,e[i].w);
    	}
    	int ans1=0,ans2=0;
    	for(i=2;i<=n;i++){
    		int tmp=ask(1,1,n,in[i]);
    		if(tmp==inf){
    			puts("-1");
    			return 0;
    		}
    		ans1+=tmp;
    	}
    	for(i=1;i<=m;i++){
    		if(vis[i]) ans2+=e[i].w;
    	}
    	printf("%lld
    ",ans1-ans2);
    	return 0;
    }
    
  • 相关阅读:
    【转】 GetProcAddress()用法
    AutoCAD开发小记
    Visual Studio 2015正式版发布
    【VS2010]如何删除【附加依赖项】中“继承的值”?
    OpenCV入门指南
    Visual Studio 遇到了异常。这可能是由某个扩展导致的。
    VS2010在WIN7下安装报错“下列组件安装失败”如何解决
    获取系统日期时间的简单方法
    免费在线pdf互转工具
    应用层vc实现三种文件监视方法
  • 原文地址:https://www.cnblogs.com/LSlzf/p/12208150.html
Copyright © 2020-2023  润新知