bzoj1977 [BeiJing2010组队]次小生成树 Tree

  和倍增法求lca差不多,维护每个点往上跳2^i步能到达的点,以及之间的边的最大值和次大值,先求出最小生成树,对于每个非树边枚举其端点在树上的路径的最大值,如果最大值和非树边权值一样则找次大值,然后维护答案即可。

  代码

  1 #include<cstdio>
  2 #include<algorithm>
  3 using namespace std;
  4 const int N = 201010;
  5 const int M = 1000100;
  6 const int inf = 2000000000;
  7 int f[N],n,m,i;
  8 int dp,p[N],pre[M],tt[M],ww[M],flag[M];
  9 int deep[N],jump[N][18],mi[N][18],Mi[N][18];
 10 long long ans,Ans;
 11 struct g{
 12     int l,r,v;
 13 }a[M];
 14 void link(int x,int y,int z)
 15 {
 16     dp++;pre[dp]=p[x];p[x]=dp;tt[dp]=y;ww[dp]=z;
 17 }
 18 bool cmp(g a,g b)
 19 {
 20     return a.v<b.v;
 21 }
 22 int gf(int x)
 23 {
 24     while (x!=f[x]) x=f[x];return x;
 25 }
 26 void dfs(int x,int fa,int va)
 27 {
 28     deep[x]=deep[fa]+1;
 29     jump[x][0]=fa;
 30     mi[x][0]=va;
 31     Mi[x][0]=-inf; 
 32     int i;
 33     for (i=1;i<=17;i++)
 34     {
 35         jump[x][i]=jump[jump[x][i-1]][i-1];
 36         mi[x][i]=max(mi[x][i-1],mi[jump[x][i-1]][i-1]);
 37         if (mi[x][i-1]==mi[jump[x][i-1]][i-1])
 38             Mi[x][i]=max(Mi[x][i-1],Mi[jump[x][i-1]][i-1]);
 39         else
 40         if (mi[x][i-1]<mi[jump[x][i-1]][i-1])
 41             Mi[x][i]=max(mi[x][i-1],Mi[jump[x][i-1]][i-1]);
 42         else
 43             Mi[x][i]=max(Mi[x][i-1],mi[jump[x][i-1]][i-1]);
 44     }
 45     i=p[x];
 46     while (i)
 47     {
 48         if (tt[i]!=fa)
 49         dfs(tt[i],x,ww[i]);
 50         i=pre[i];
 51     }
 52 }
 53 void updata(int x,int y,int &ans,int &Ans)
 54 {
 55     if (x>=ans)
 56     {
 57         if (x>ans)
 58         Ans=max(Ans,ans);
 59         Ans=max(Ans,y);
 60         ans=x;
 61     }
 62     else
 63     if (x>Ans)
 64         Ans=max(Ans,x);
 65 }
 66 int get(int a,int b,int c)
 67 {
 68     if (deep[a]<deep[b]) a^=b^=a^=b;
 69     int i,ans=-inf,Ans=-inf;
 70     for (i=17;i>=0;i--)
 71     if (deep[jump[a][i]]>=deep[b])
 72     {
 73         updata(mi[a][i],Mi[a][i],ans,Ans);
 74         a=jump[a][i];
 75     }
 76     if (a==b) 
 77     {
 78         if (ans==c) return Ans;else return ans;
 79     }
 80     for (i=17;i>=0;i--)
 81     if (jump[a][i]!=jump[b][i])
 82     {
 83         updata(mi[a][i],Mi[a][i],ans,Ans);
 84         updata(mi[b][i],Mi[b][i],ans,Ans);
 85         a=jump[a][i];b=jump[b][i];    
 86     }
 87     updata(mi[a][0],Mi[a][0],ans,Ans);
 88     updata(mi[b][0],Mi[b][0],ans,Ans);
 89     if (ans==c) return Ans;else return ans;
 90 }
 91 int main()
 92 {
 93     scanf("%d%d",&n,&m);
 94     for (i=1;i<=m;i++)
 95         scanf("%d%d%d",&a[i].l,&a[i].r,&a[i].v);
 96     sort(a+1,a+1+m,cmp);
 97     for (i=1;i<=n;i++) f[i]=i;
 98     for (i=1;i<=m;i++)
 99     {
100         int l=a[i].l,r=a[i].r;
101         if (gf(l)!=gf(r))
102         {
103             link(l,r,a[i].v);
104             link(r,l,a[i].v);
105             f[gf(l)]=gf(r);
106             Ans+=a[i].v;
107             flag[i]=1;
108         }
109     }
110     dfs(1,0,0);
111     ans=(long long) inf*inf;
112     for (i=1;i<=m;i++)
113     if (!flag[i])
114     {
115         long long tmp=Ans-get(a[i].l,a[i].r,a[i].v)+a[i].v;
116         if ((tmp>Ans)&&(tmp<ans)) ans=tmp;
117     }
118     printf("%lld
",ans);
119 }
原文地址:https://www.cnblogs.com/fzmh/p/5510055.html