luogu P2700 逐个击破

思维题,套路题。

本来想在学完树形dp,开始做数据结构前刷几道水题愉悦一下身心,结果tm直接匹配了一道不用树形dp十分有意思的题

思路:考虑题目的转化:将删除的边数最小转化为留下的权值最大,用kruskal的思想加边,如果两点都是敌人直接切,如果一方是敌人,先不管,将另一方感染为敌人。这也是拆边连通性问题的一般思路。

code:

#include<bits/stdc++.h>
#define IL inline
#define RI register int
IL void in(int &x)
{
    int f=1;x=0;char s=getchar();
    while(s>'9' or s<'0'){if(s=='-')f=-1;s=getchar();}
    while(s>='0' and s<='9'){x=x*10+s-'0';s=getchar();}
    x*=f;
}
int n,k,f[100008],tot;
bool init[1000008];
long long ans;
struct cod{int u,v,w;}edge[100008];
IL int find(int x){return f[x]==x?x:f[x]=find(f[x]);}
IL bool ccp(const cod&a,const cod&b){return a.w>b.w;}
int main(void)
{
    in(n),in(k);
    for(RI i=1;i<=n;i++)f[i]=i;
    for(RI i=1,x;i<=k;i++)in(x),init[x]=true;
    for(RI i=1;i<=n-1;i++)
        in(edge[i].u),in(edge[i].v),in(edge[i].w),ans+=edge[i].w;
    std::sort(edge+1,edge+n,ccp);
    for(RI i=1;i<=n-1;i++)
    {
        int u=edge[i].u,v=edge[i].v,w=edge[i].w;
        int fu=find(u),fv=find(v);
        if(init[fu] and init[fv])continue;
        f[fu]=fv;
        ans-=w;
    }
    printf("%lld",ans);
}

收获:有时用并查集可以解决这类连通性问题(路径压缩),还有注意题目的转化

转载于:https://www.cnblogs.com/bullshit/p/9643135.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值