BZOJ3206: [Apio2013]道路费用

8 篇文章 0 订阅
7 篇文章 0 订阅

表达一下深深的怨念

题面保证了边权互不相同,然鹅我做这题的时候狂WA不止,对拍只有边权相同的时候能拍出来,交到uoj上也过了
我就怀疑数据有问题qwq
于是扒了一个AC代码,加了判如果有相同边权,输出了一些脏话qwq
然后0msWA了
注释掉这行
A掉了
…….

要了数据
这数据…一半以上一堆相同边权的吧….

边权互不相同保证了不考虑操作边的MST唯一,不保证相同边权…似乎不太可做?
辣鸡数据

题解部分:

我们先将可操作的边全部赋负权,建出原图的MST
这棵树上的正权边,无论你给操作边赋什么值都一定会在最终的MST上
所以用这些边将原图缩到O(k)个点,O(k^2)条边
再对缩点后的图建MST(不用那些操作边),这时MST上的边集S就是可能出现在最终的MST上的边
因为k不大,可以2^k枚举用哪些边,建出最终的MST
这时,因为kruskal的性质(联想建树的过程..),如果有一条边权为c的边(u,v)不在MST上,那么MST上的所有边权都<=c
我们只需要考虑S中的边对MST中的边权的影响(其他边不需要考虑,意会一下?),暴力在维护路径上操作边的边权
复杂度 O(mlogm+2kk2)

code:

#include<set>
#include<map>
#include<deque>
#include<queue>
#include<stack>
#include<cmath>
#include<ctime>
#include<bitset>
#include<string>
#include<vector>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<climits>
#include<complex>
#include<iostream>
#include<algorithm>
#define ll long long
#define inf 1e6+1
using namespace std;

inline void read(int &x)
{
    char c; while(!((c=getchar())>='0'&&c<='9'));
    x=c-'0';
    while((c=getchar())>='0'&&c<='9') (x*=10)+=c-'0';
}
inline void down(int &x,const int &y){if(x>y)x=y;}
const int maxn = 210000;
const int maxm = 410000;
const int maxk = 25;

int n,m,K;
struct edge{int x,y,c;}a[maxm],b[maxk],c[maxn]; int an,bn,cn;
inline bool cmp(const edge x,const edge y){return x.c<y.c;}

int fa[maxn];
int findfa(const int x){return fa[x]==x?x:fa[x]=findfa(fa[x]);}

int idt[maxn]; ll num[maxn];
int pn,ci[maxk][maxk];

struct node{int y,i,nex;}e[maxm]; int len,fir[maxk];
inline void ins(const int x,const int y,const int i){e[++len]=(node){y,i,fir[x]};fir[x]=len;}
int val[maxk*2],fai[maxk];
int dep[maxk],Fa[maxn];
ll temp,siz[maxk];
void dfs(const int x)
{
    siz[x]=num[x];
    for(int k=fir[x],y=e[k].y;k;k=e[k].nex,y=e[k].y) if(y!=Fa[x])
    {
        dep[y]=dep[x]+1; Fa[y]=x;
        if(e[k].i) fai[y]=e[k].i;
        dfs(y);
        siz[x]+=siz[y];
    }
}

ll re;

int main()
{
    read(n); read(m); read(K); an=m; bn=K;
    for(int i=1;i<=m;i++) read(a[i].x),read(a[i].y),read(a[i].c);
    for(int i=1;i<=bn;i++)
    {
        int x,y; read(x); read(y);
        a[++an]=b[i]=(edge){x,y,-1};
    }

    sort(a+1,a+an+1,cmp);
    for(int i=1;i<=n;i++) fa[i]=i;
    for(int i=1;i<=an;i++)
    {
        int x=a[i].x,y=a[i].y;
        int f1=findfa(x),f2=findfa(y);
        if(f1!=f2) fa[f1]=f2,c[++cn]=a[i];
    }

    for(int i=1;i<=n;i++) fa[i]=i;
    for(int i=1;i<=cn;i++) if(c[i].c>0)
        fa[findfa(c[i].x)]=findfa(c[i].y);
    for(int i=1;i<=n;i++) if(findfa(i)==i)
        idt[i]=++pn;
    for(int i=1;i<=n;i++) 
    {
        int x; read(x);
        idt[i]=idt[findfa(i)],num[idt[i]]+=(ll)x;
    }

    memset(ci,63,sizeof ci);
    for(int i=1;i<=an;i++) if(a[i].c>0)
    {
        int x=idt[findfa(a[i].x)],y=idt[findfa(a[i].y)];
        if(x!=y) down(ci[x][y],a[i].c),down(ci[y][x],a[i].c);
    }

    cn=0;
    for(int i=1;i<=pn;i++) for(int j=1;j<=pn;j++) if(ci[i][j]<inf) 
        c[++cn]=(edge){i,j,ci[i][j]};
    sort(c+1,c+cn+1,cmp);
    for(int i=1;i<=pn;i++) fa[i]=i;
    an=0;
    for(int i=1;i<=cn;i++)
    {
        int x=c[i].x,y=c[i].y;
        int f1=findfa(x),f2=findfa(y);
        if(f1!=f2) a[++an]=c[i],fa[f1]=f2;
    }

    re=0;
    for(int i=1;i<(1<<bn);i++)
    {
        for(int j=1;j<=pn;j++) fa[j]=j,fai[j]=0;
        for(int j=1;j<=pn;j++) fir[j]=0; len=0;

        bool flag=true;
        for(int j=1;j<=bn;j++) if(i>>j-1&1)
        {
            int x=idt[b[j].x],y=idt[b[j].y];
            int f1=findfa(x),f2=findfa(y);
            if(f1==f2) { flag=false; break; }
            fa[f1]=f2;
            ins(x,y,j*2+1); ins(y,x,j*2);
            val[j*2+1]=val[j*2]=inf;
        }
        if(!flag) continue;
        for(int j=1;j<=an;j++)
        {
            int x=a[j].x,y=a[j].y;
            int f1=findfa(x),f2=findfa(y);
            if(f1!=f2) ins(x,y,0),ins(y,x,0),fa[f1]=f2;
        }
        dep[idt[1]]=1; dfs(idt[1]);
        temp=0;
        for(int j=1;j<=an;j++)
        {
            int x=a[j].x,y=a[j].y;
            if(dep[x]<dep[y]) swap(x,y);
            while(dep[x]>dep[y])
            {
                if(fai[x]) down(val[fai[x]],a[j].c);
                x=Fa[x];
            }
            while(x!=y)
            {
                if(fai[x]) down(val[fai[x]],a[j].c);
                if(fai[y]) down(val[fai[y]],a[j].c);
                x=Fa[x],y=Fa[y];
            }
        }
        for(int j=1;j<=len;j++) if(e[j].i&&val[e[j].i]<inf) temp+=(ll)val[e[j].i]*siz[e[j].y];
        re=max(re,temp);
    }
    printf("%lld\n",re);

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值