zoukankan      html  css  js  c++  java
  • BZOJ 1977: [BeiJing2010组队]次小生成树(Kruskal+树上倍增)


    1977: [BeiJing2010组队] 次小生成树 Tree

      Time Limit: 10 Sec
      Memory Limit: 512 MB

    Description###

      小 C 最近学了很多最小生成树的算法,Prim 算法、Kurskal 算法、消圈算法等等。 正当>小 C 洋洋得意之时,小 P 又来泼小 C 冷水了。小 P 说,让小 C 求出一个无向图的次小生成
    树,而且这个次小生成树还得是严格次小的,也就是说: 如果最小生成树选择的边集是 >EM,严格次小生成树选择的边集是 ES,那么需要满足:
      
                这里写图片描述
    这下小 C 蒙了,他找到了你,希望你帮他解决这个问题。
      

    Input###

      第一行包含两个整数N 和M,表示无向图的点数与边数。 接下来 M行,每行 3个数x y z >表示,点 x 和点y之间有一条边,边的权值为z。。
      

    Output###

      包含一行,仅一个数,表示严格次小生成树的边权和。(数据保证必定存在严格次小生成树)
      

    Sample Input 1###

      5 6
      1 2 1
      1 3 2
      2 4 3
      3 5 4
      3 4 3
      4 5 6
      

    Sample Output 1###

      11
      

    HINT###

      数据中无向图无自环;
      50% 的数据N≤2 000 M≤3 000;
      80% 的数据N≤50 000 M≤100 000;
      100% 的数据N>≤100 000 M≤300 000 ,边权值非负且不超过 10^9 。
      

    题目地址: BZOJ 1977: [BeiJing2010组队]次小生成树

    题解:

         
      先求出最小生成树,然后枚举每条不在该树上的边  
      求出此边两点的树上路径中小于此边长度的最大的边(题目要求严格次小
      可用树上倍增解决,因为最大的边可能等于枚举的边,所以还要求出严格次大的边
      虽然很水但我还是被优先级和初值坑了三个小时QWQ
    www.cnblogs.com/AGFghy/


    AC代码

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    typedef long long ll;
    struct path
    {
        int x,y,l;
    }p[300005];
    int n,m,num,f1,f2;
    ll now,sum,n1,n2,ans;
    int point[200005],len[200005],Next[200005],head[100005],fa[100005],dep[100005],mark[100005],f[100005][25];
    ll mx1[100005][25],mx2[100005][25];
    bool cmp(path p1,path p2)
    {
        return p1.l<p2.l;
    }
    int find(int k)
    {
        if (k!=fa[k]) return fa[k]=find(fa[k]);
        return k;
    }
    void add(int u,int v,int nl)
    {
        num++;
        point[num]=v;
        len[num]=nl;
        Next[num]=head[u];
        head[u]=num;
    }
    void find(int now,int pre)
    {
        dep[now]=dep[pre]+1;
        f[now][0]=pre;
        for (int i=head[now]; i!=-1; i=Next[i])
        {
            int v=point[i];
            if (v!=pre) 
            {
                mx1[v][0]=len[i];
                find(v,now);
            }
        }
    }
    ll max(ll x,ll y)
    {
        if (x>y) return x;
        return y;
    }
    ll min(ll x,ll y)
    {
        if (x<y) return x;
        return y;
    }
    void lca(int u,int v)
    {
        if (dep[u]<dep[v]) swap(u,v);
        int deep=dep[u]-dep[v];
        for (int i=0; i<=20; i++)
            if ((deep&(1<<i))>0) 
            {
                n2=max(n2,mx2[u][i]);
                if (n1!=mx1[u][i]) n2=max(n2,min(n1,mx1[u][i]));
                n1=max(n1,mx1[u][i]);
                u=f[u][i];
            }
        for (int i=20; i>=0; i--)
            if (f[u][i]!=f[v][i])
            {
                n2=max(n2,mx2[u][i]);
                if (n1!=mx1[u][i]) n2=max(n2,min(n1,mx1[u][i]));
                n1=max(n1,mx1[u][i]);
                u=f[u][i];
                  
                n2=max(n2,mx2[v][i]);
                if (n1!=mx1[v][i]) n2=max(n2,min(n1,mx1[v][i]));
                n1=max(n1,mx1[v][i]);
                v=f[v][i];
            }
        if (u!=v)
        {
            n2=max(n2,mx2[u][0]);
            if (n1!=mx1[u][0]) n2=max(n2,min(n1,mx1[u][0]));
            n1=max(n1,mx1[u][0]);
              
            n2=max(n2,mx2[v][0]);
            if (n1!=mx1[v][0]) n2=max(n2,min(n1,mx1[v][0]));
            n1=max(n1,mx1[v][0]);
        } 
        return;
    }
    int main()
    {
        scanf("%d%d",&n,&m);
        for (int i=1; i<=n; i++)
            head[i]=-1;
        for (int i=1; i<=m; i++)
            scanf("%d%d%d",&p[i].x,&p[i].y,&p[i].l);
             
        sort(p+1,p+m+1,cmp);
        for (int i=1; i<=n; i++)
            fa[i]=i;
        now=n-1;
        for (int i=1; i<=m; i++)
        {
            f1=find(p[i].x);
            f2=find(p[i].y);
            if (f1!=f2)
            {
                now--;
                fa[f2]=f1;
                sum+=p[i].l;
                mark[i]=1;
                add(p[i].x,p[i].y,p[i].l);
                add(p[i].y,p[i].x,p[i].l);
                if (now==0) break;
            }
        }
        memset(mx1,-1,sizeof(mx1));
        memset(mx2,-1,sizeof(mx2));
        find(1,0);
        for (int j=1; j<=20; j++)
            for (int i=1; i<=n; i++)
            if (f[i][j-1])
            {
                f[i][j]=f[f[i][j-1]][j-1];
                mx1[i][j]=max(mx1[i][j-1],mx1[f[i][j-1]][j-1]);
                if (mx1[i][j-1]!=mx1[f[i][j-1]][j-1]) mx2[i][j]=min(mx1[i][j-1],mx1[f[i][j-1]][j-1]);
                mx2[i][j]=max(mx2[i][j],max(mx2[i][j-1],mx2[f[i][j-1]][j-1]));
            }
        ans=1ll<<50;
        for (int i=1; i<=m; i++)
            if (mark[i]==0)
            {
                n1=-1; n2=-1;
                lca(p[i].x,p[i].y);
                if (n1!=p[i].l) 
                {
                    now=sum+p[i].l-n1;
                    ans=min(ans,now);
                }
                else if (n2!=-1)
                {
                    now=sum+p[i].l-n2;
                    ans=min(ans,now);
                }
            }
        printf("%lld\n",ans);
        return 0;
    }
    
  • 相关阅读:
    关于cmake、make、make install
    windows开启ip_forwarding功能
    最新devstack安装(ussuri)
    【rabbitmq】之业务封装
    【rabbitmq】之过期和死信队列
    【rabbitmq】之confirm和return机制
    【rabbitmq】之消费端手动ack
    java短网址服务
    详解druid打印SQL日志
    logback配置文件拆分,抽取公共配置
  • 原文地址:https://www.cnblogs.com/AGFghy/p/9337654.html
Copyright © 2011-2022 走看看