zoukankan      html  css  js  c++  java
  • 「LuoguP4180」 【模板】严格次小生成树[BJWC2010](倍增 LCA Kruscal

    题目描述

    小C最近学了很多最小生成树的算法,Prim算法、Kurskal算法、消圈算法等等。正当小C洋洋得意之时,小P又来泼小C冷水了。小P说,让小C求出一个无向图的次小生成树,而且这个次小生成树还得是严格次小的,也就是说:如果最小生成树选择的边集是EM,严格次小生成树选择的边集是ES,那么需要满足:(value(e)表示边e的权值) sum_{e in E_M}value(e)<sum_{e in E_S}value(e)eEMvalue(e)<eESvalue(e)

    这下小 C 蒙了,他找到了你,希望你帮他解决这个问题。

    输入输出格式

    输入格式:

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

    输出格式:

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

    输入输出样例

    输入样例#1: 复制
    5 6
    1 2 1 
    1 3 2 
    2 4 3 
    3 5 4 
    3 4 3 
    4 5 6 
    输出样例#1: 复制
    11

    说明

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

    题解

    话说这个还没有经典到当模板吧qwq

    先做一个最小生成树,图被分成树边和非树边。

    在这个树上随便找个点当根,预处理好倍增的东西(包括往上$2^j$步的祖先编号,往祖先走的这条路上最长的边,这条路上第二长的边

    然后把每条非树边跑一遍,设两点为$u,v$。

    可以想到,从$u$到$v$的这条树上路径中找一条最大但小于这条非树边的边替换,这样的结果是严格次小生成树的一个备选结果。

    所以就一边求lca一边跟那一段的最长边和第二长边对比啊什么的。

    //记录第二长边主要是防止最长边和这条非树边一样长

    作为紫题非常好写,非常不容易错。(毕竟只是倍增lca和Kruscal揉到一起的一个东西,元件都不难写qwq

    但确实很长就是了qwq

      1 /*
      2     qwerta 
      3     P4180 【模板】严格次小生成树[BJWC2010] Accepted 
      4     100
      5     代码 C++,2.72KB
      6     提交时间 2018-10-31 19:50:25
      7     耗时/内存 1812ms, 35376KB
      8 */
      9 #include<algorithm>
     10 #include<iostream>
     11 #include<cstring>
     12 #include<cstdio>
     13 #include<cmath>
     14 using namespace std;
     15 inline int read()
     16 {
     17     char ch=getchar();
     18     int x=0;
     19     while(!isdigit(ch))ch=getchar();
     20     while(isdigit(ch)){x=x*10+ch-'0';ch=getchar();}
     21     return x;
     22 }
     23 const int MAXN=1e5+3,MAXM=3e5+3;
     24 struct emm{
     25     int x,y,l,tag;
     26 }b[MAXM];//用来存原图,tag表示是否为树边
     27 bool cmp(emm qaq,emm qwq){
     28     return qaq.l<qwq.l;
     29 }//用来最小生成树
     30 int fa[MAXN];
     31 int fifa(int x)
     32 {
     33     if(fa[x]==x)return x;
     34     return fa[x]=fifa(fa[x]);
     35 }
     36 struct ahh{
     37     int e,f,l;
     38 }a[2*MAXN];//用来存树
     39 int h[MAXN];
     40 int tot=0;
     41 void con(int x,int y,int l)//连树边
     42 {
     43     a[++tot].f=h[x];
     44     h[x]=tot;
     45     a[tot].e=y;
     46     a[tot].l=l;
     47     a[++tot].f=h[y];
     48     h[y]=tot;
     49     a[tot].e=x;
     50     a[tot].l=l;
     51     return;
     52 }
     53 int w[MAXN],d[MAXN];//w把边权记在深度较深的点上,d为深度
     54 void dfs(int x)//dfs建树
     55 {
     56     for(int i=h[x];i;i=a[i].f)
     57     if(!d[a[i].e])
     58     {
     59         fa[a[i].e]=x;
     60         d[a[i].e]=d[x]+1;
     61         w[a[i].e]=a[i].l;
     62         dfs(a[i].e);
     63     }
     64     return;
     65 }
     66 int f[MAXN][21];//往上2^j步的祖先
     67 int mac[MAXN][21];//往上2^j步途中最长的边长
     68 int macc[MAXN][21];//往上2^j步途中严格第二长的边长
     69 int zz[5];//辅助数组
     70 bool cmpp(int qaq,int qwq){
     71     return qaq>qwq;
     72 }//用来给zz排序
     73 int main()
     74 {
     75     //freopen("a.in","r",stdin);
     76     int n=read(),m=read();
     77     for(int i=1;i<=m;++i)
     78     {
     79         b[i].x=read(),b[i].y=read(),b[i].l=read();
     80     }
     81     //做个最小生成树↓
     82     sort(b+1,b+m+1,cmp);
     83     for(int i=1;i<=n;++i)
     84     fa[i]=i;
     85     int k=n-1,j=0;
     86     long long sum=0;
     87     while(k)
     88     {
     89         j++;
     90         int u=fifa(b[j].x),v=fifa(b[j].y);
     91         if(u!=v)
     92         {
     93             fa[u]=v;
     94             //cout<<b[j].x<<" "<<b[j].y<<" "<<b[j].l<<endl;
     95             b[j].tag=1;
     96             sum+=b[j].l;//记下树边权值和
     97             con(b[j].x,b[j].y,b[j].l);//把两点连起来
     98             k--;
     99         }
    100     }
    101     //dfs建树↓
    102     memset(fa,0,sizeof(fa));
    103     int s=min(n,7);
    104     d[s]=1;
    105     dfs(s);
    106     //倍增↓
    107     for(int i=1;i<=n;++i)
    108     {
    109         // /cout<<i<<" "<<fa[i]<<endl;
    110         f[i][0]=fa[i];
    111         mac[i][0]=w[i];
    112     }
    113     for(int j=1;j<=14;++j)
    114     for(int i=1;i+(1<<j)-1<=n;++i)
    115     {
    116         f[i][j]=f[f[i][j-1]][j-1];
    117         zz[1]=mac[i][j-1],zz[2]=macc[i][j-1];
    118         zz[3]=mac[f[i][j-1]][j-1],zz[4]=macc[f[i][j-1]][j-1];
    119         //这里用zz只是懒得写if
    120         sort(zz+1,zz+5,cmpp);//从大到小sort一下
    121         unique(zz+1,zz+5);//因为要严格第二大所以unique一下
    122         mac[i][j]=zz[1];
    123         macc[i][j]=zz[2];
    124     }
    125     long long ans=1e14+2333;
    126     for(int i=1;i<=m;++i)
    127     if(!b[i].tag)//循环每条非树边
    128     {
    129         int u=b[i].x,v=b[i].y;
    130         //倍增求lca
    131         if(d[u]<d[v])swap(u,v);
    132         for(int j=14;j>=0;--j)
    133         if(d[u]-d[v]>=(1<<j))
    134         {
    135             if(b[i].l>mac[u][j])//如果非树边比最长边长
    136             ans=min(ans,sum-mac[u][j]+b[i].l);//这两条替换是一种可能方案
    137             else if(b[i].l==mac[u][j])//否则如果非树边跟最长边一样长
    138             ans=min(ans,sum-macc[u][j]+b[i].l);//把这条边跟第二长边替换是一种可能方案
    139             u=f[u][j];//记得往上跳
    140         }
    141         if(u==v)continue;
    142         for(int j=14;j>=0;--j)
    143         if(f[u][j]!=f[v][j])
    144         {
    145             if(b[i].l>mac[u][j])
    146             ans=min(ans,sum-mac[u][j]+b[i].l);
    147             else if(b[i].l==mac[u][j])
    148             ans=min(ans,sum-macc[u][j]+b[i].l);
    149             u=f[u][j];
    150             if(b[i].l>mac[v][j])
    151             ans=min(ans,sum-mac[v][j]+b[i].l);
    152             else if(b[i].l==mac[v][j])
    153             ans=min(ans,sum-macc[v][j]+b[i].l);
    154             v=f[v][j];
    155         }
    156         if(b[i].l>w[u])
    157         ans=min(ans,sum-w[u]+b[i].l);
    158         if(b[i].l>w[v])
    159         ans=min(ans,sum-w[v]+b[i].l);
    160     }
    161     cout<<ans<<endl;//输出撒花
    162     return 0;
    163 }
  • 相关阅读:
    .net的委托和事件的直接理解[转载]
    虚函数 多态 函数重载[转载]
    自动化 object <> xml
    用System.Web.HttpRequest模拟一个form的post
    【WP7】动画的使用
    【WP7】关于ListBox控件的数据绑定
    【WP7】坐标变换
    【WP7】页面之间数据交互
    【WP7】调用系统LED灯
    【WP7】MediaPlayer与关闭音乐的方法
  • 原文地址:https://www.cnblogs.com/qwerta/p/9886338.html
Copyright © 2011-2022 走看看