• [BZOJ1977]严格次小生成树


    【问题描述】

      小C最近学了很多最小生成树的算法,Prim算法、Kurskal算法、消圈算法等等。

      正当小C洋洋得意之时,小P又来泼小C冷水了。小P说,让小C求出一个无向图的次小生成树,而且这个次小生成树还得是严格次小的,也就是说:如果最小生成树选择的边集是EM,严格次小生成树选择的边集是ES,那么需要满足:(value(e)表示边e的权值) 
       这里写图片描述 
              
      这下小C蒙了,他找到了你,希望你帮他解决这个问题。

    【输入格式】

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

    【输出格式】

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

    【输入样例】

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

    【输出样例】

    11 
    

    【数据范围】

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

    题解:

    要求求严格次小生成树,首先kruskal就无法使用,prim复杂度太高

    于是我们用LCA

    构造出最小生成树,可知次小生成树肯定是加入某边再删去一边

    假设加入(i,j)则有删去生成树上i~j路径最大的边,用倍增维护

    但是严格次小没有解决

    可以在用倍增维护最大值时,再维护次小值,那么当最大值等于加入边权值时则删去次大边

      1 #include<iostream>
      2 #include<cstdio>
      3 #include<algorithm>
      4 #include<cstring>
      5 using namespace std;
      6 typedef long long lol;
      7 struct Messi
      8 {
      9     lol u,v;
     10     lol dis;
     11 }edge1[500001];
     12 struct Node
     13 {
     14     lol next,to;
     15     lol dis;
     16 }edge[100001];
     17 lol num,head[100001],set[100001],depth[100001],Max[100001][18],Max2[100001][18],fa[100001][18],n,m,ans1,ans=2e9;
     18 bool vis[100001],b[500001];
     19 bool cmp(Messi a,Messi b)
     20 {
     21     return a.dis<b.dis;
     22 }
     23 void add(lol u,lol v,lol dis)
     24 {
     25     num++;
     26     edge[num].next=head[u];
     27     head[u]=num;
     28     edge[num].to=v;
     29     edge[num].dis=dis;
     30 }
     31 lol find(lol x)
     32 {
     33     if (set[x]!=x) set[x]=find(set[x]);
     34     return set[x];
     35 }
     36 void dfs(lol x,lol dep)
     37 {int i;
     38     vis[x]=1;
     39     depth[x]=dep;
     40     for (i=1;i<=17;i++)
     41     if (dep>(1<<i))
     42     {
     43         Max[x][i]=max(Max[x][i-1],Max[fa[x][i-1]][i-1]);
     44         if (Max[x][i-1]!=Max[fa[x][i-1]][i-1]) Max2[x][i]=Max[x][i-1]+Max[fa[x][i-1]][i-1]-Max[x][i];
     45         Max2[x][i]=max(Max2[x][i],max(Max2[x][i-1],Max2[fa[x][i-1]][i-1]));
     46         fa[x][i]=fa[fa[x][i-1]][i-1];
     47     }
     48     for (i=head[x];i;i=edge[i].next)
     49     {
     50         int v=edge[i].to;
     51         if (vis[v]==0)
     52         {
     53             fa[v][0]=x;
     54             Max[v][0]=edge[i].dis;
     55             dfs(v,dep+1);
     56         }
     57     }
     58 }
     59 lol ask(lol x,lol y,lol d)
     60 {int i;
     61     lol s1=0,s2=0;
     62     if (depth[x]<depth[y]) swap(x,y);
     63     for (i=17;i>=0;i--)
     64      if ((1<<i)<=depth[x]-depth[y])
     65       {
     66           if (s1!=Max[x][i]) s2=max(s2,min(s1,Max[x][i]));
     67           s2=max(s2,Max2[x][i]);
     68           s1=max(s1,Max[x][i]);
     69        x=fa[x][i];
     70       }
     71     if (x==y) 
     72     {
     73         if (s1==d&&s2) return d-s2;
     74         else if (s2==0) return 2e9;
     75         else if (s1!=d)return d-s1;
     76     }
     77     for (i=17;i>=0;i--)
     78     {
     79       if ((1<<i)<depth[x]&&fa[x][i]!=fa[y][i])
     80         {
     81         if (s1!=Max[x][i]) s2=max(s2,min(s1,Max[x][i]));
     82           s2=max(s2,Max2[x][i]);
     83           s1=max(s1,Max[x][i]);
     84         if (s1!=Max[y][i]) s2=max(s2,min(s1,Max[y][i]));
     85           s2=max(s2,Max2[y][i]);
     86           s1=max(s1,Max[y][i]);    
     87             x=fa[x][i];y=fa[y][i];
     88         }           
     89     }
     90     if (s1!=Max[x][0]) s2=max(s2,min(s1,Max[x][0]));
     91           s2=max(s2,Max2[x][0]);
     92           s1=max(s1,Max[x][0]);
     93         if (s1!=Max[y][0]) s2=max(s2,min(s1,Max[y][0]));
     94           s2=max(s2,Max2[y][0]);
     95           s1=max(s1,Max[y][0]);
     96     x=fa[x][0];y=fa[y][0];
     97     if (s1==d&&s2) return d-s2;
     98         else if (s2==0) return 2e9;
     99         else if (s1!=d)return d-s1;
    100 }
    101 int main()
    102 {int i,j,q,opt,x,y;
    103 //freopen("scrip.in","r",stdin);
    104 //freopen("scrip.out","w",stdout);
    105     cin>>n>>m;
    106     for (i=1;i<=m;i++)
    107     {
    108         scanf("%d%d%d",&edge1[i].u,&edge1[i].v,&edge1[i].dis);
    109     }
    110     sort(edge1+1,edge1+m+1,cmp);
    111     for (i=1;i<=n;i++)
    112     set[i]=i;
    113     i=1;j=1;
    114      while (i<=n-1&&j<=m)
    115      {
    116          int p=find(edge1[j].u),q=find(edge1[j].v);
    117              if (p!=q)
    118              {
    119               set[p]=q;
    120               i++;
    121               b[j]=1;
    122               ans1+=edge1[j].dis;
    123               add(edge1[j].u,edge1[j].v,edge1[j].dis);
    124               add(edge1[j].v,edge1[j].u,edge1[j].dis);
    125             }
    126             j++;
    127      }
    128      if (i<=n-1)
    129      {
    130          cout<<"No MST!";
    131          return 0;
    132      }
    133      dfs(1,1);
    134      for (j=1;j<=m;j++)
    135      {
    136           if (b[j]==0)
    137           {
    138                ans=min(ans,ask(edge1[j].u,edge1[j].v,edge1[j].dis));
    139           } 
    140      }
    141     if (ans==2e9)
    142     {
    143         cout<<"No SST!";
    144         return 0;
    145     }
    146 cout<<ans+ans1;
    147 }
  • 相关阅读:
    python 协程
    python 进程池的使用
    python 多进程数据交互及共享
    python 多进程
    技术博客与技术日记
    理解闭包
    jWriter一个基于jQuery的阅读写作网站的效果库
    ubuntu下phpmyadmin配置问题解决
    避免明文保存用户密码
    如何用css实现类似简书的纵向导航/竖排导航
  • 原文地址:https://www.cnblogs.com/Y-E-T-I/p/7251077.html
Copyright © 2020-2023  润新知