[联合集训6-18] 奥妮的大楼

问题转化就是给定 n n 个二元组,每组中选出一个使得其互不相同,最大化另一个的和。
那么对于每个二元组我们对这两个值连一条无向边,现在的问题就是对每一条边定向使得每个点出度1,并最大化每个点乘上其入度的和。
那么有解一定是若干个树和环套树,对于环套树的情况定向方式是唯一的,这样每个点贡献 degi1 d e g i − 1 次, degi d e g i 表示其度数;对于树的情况根节点可以多贡献一次,我们选出其中最大的贡献 degi d e g i 次,其它的贡献 degi1 d e g i − 1 次即可。
代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define N 250010
#define ll long long
using namespace std;
int m,n,tote,a[N],b[N],con[N<<1],nxt[N<<2],to[N<<2],mx,z[N<<1],deg[N<<1];
ll ans;
bool vis[N<<1],flag;
void ins(int x,int y)
{
    to[++tote]=y;
    nxt[tote]=con[x];
    con[x]=tote;
}
void dfs(int v,int q)
{
    mx=max(mx,z[v]);vis[v]=1;
    for(int p=con[v];p;p=nxt[p])
        if((p^q)!=1)
            if(vis[to[p]]) flag=1;
            else dfs(to[p],p);
}

int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
    {
        scanf("%d%d",&a[i],&b[i]);
        z[2*i-1]=a[i];z[2*i]=b[i];
    }
    sort(z+1,z+2*n+1);
    m=unique(z+1,z+2*n+1)-z-1;
    tote=1;
    for(int i=1;i<=n;i++)
    {
        int x=lower_bound(z+1,z+m+1,a[i])-z,y=lower_bound(z+1,z+m+1,b[i])-z;
        ins(x,y);ins(y,x);
        deg[x]++;deg[y]++;
    }
    for(int i=1;i<=m;i++)
        if(!vis[i]) 
        {
            flag=0;mx=0;
            dfs(i,0);
            if(!flag) ans+=mx;
        }   
    for(int i=1;i<=m;i++)
        ans+=(ll)z[i]*(deg[i]-1);
    printf("%lld",ans);     
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值