zoukankan      html  css  js  c++  java
  • bzoj2238

    给出一个NN个点MM条边的无向带权图,以及QQ个询问,每次询问在图中删掉一条边后图的最小生成树。(各询问间独立,每次询问不对之后的询问产生影响,即被删掉的边在下一条询问中依然存在)。

    ________________________________________

    一个无向图,中有两种边,生成树上的边和其它边。

    其它边删掉了,对最小生成树没有影响。

    树上的边删掉了,如果上条边没有在环上,则不能再次生成树

    在环上就可以再生成树。

    首先生成树,不以树上的边就可以得到答案了。

    枚举所有的边,如果边不在树上时,它可以和树上的某条链上的边构成环。

    明显,链上的边的边长小于等于这条非树边的长度。

    而树上的某一条边处在多环上时,如果删掉这个边,由于要构成最小生成树,那么肯定由最小非树边代替。

    所以,每一条非树边对一条链上的所有边给一个权值,只要保留最小的(别的没有用),答案就是mst-当前边权值+保留的最小值

    这个可以用树链剖分完成!

    由于,每一树条边,只有覆盖它的最小非树边是用来“再生成最小生成树”的,其它的没有用。所以可以从小到大枚举非树边,它覆盖的边都标上这条非树边的权值(由于从小到大枚举,肯定最小)。

    但是这样复杂度就变成了m*n.因为每次的链可能很长。

    这时我们会发现,标边最小值的树边不会再用大的边标(只要最小的),所以可以用并查集再进行和并。

    由于这样很条树边只会标记一次且路径压缩后不再一步步的向上跳,所以复杂度就成了n+m

    !!!!!忘了一点,这个题很恶心,他共9个点,可是有4个点的数据不能生成树,也就是不连通!!!!!!

    ________________________________________

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 const int maxn=1e5+10;
     4 int n,m,q;
     5 struct edge
     6 {
     7     int u,v,w,no,nxt;
     8 }e[maxn<<1],ee[maxn];
     9 int head[maxn],js;
    10 void addage(int u,int v,int w,int no)
    11 {
    12     e[++js].u=u;e[js].v=v;e[js].w=w;e[js].no=no;
    13     e[js].nxt=head[u];head[u]=js;
    14 }
    15 bool cmp(edge a,edge b)
    16 {
    17     return a.w<b.w;
    18 }
    19 int f[maxn],ff[maxn];
    20 int find(int *f,int x)
    21 {
    22     if(f[x]==x)return x;
    23     else return f[x]=find(f,f[x]);
    24 }
    25 int ans[maxn],fa[maxn],dep[maxn],mxt,upno[maxn];
    26 bool intr[maxn];
    27 void dfs(int u,int fat)
    28 {
    29     fa[u]=fat;ff[u]=u;dep[u]=dep[fat]+1;
    30     for(int i=head[u];i;i=e[i].nxt)
    31     {
    32         int v=e[i].v;
    33         if(v==fat)continue;
    34         upno[v]=e[i].no;
    35         dfs(v,u);
    36     }
    37 }        
    38 int main()
    39 {
    40     scanf("%d%d",&n,&m);
    41     for(int u,v,w,i=1;i<=m;++i)
    42     {
    43         scanf("%d%d%d",&ee[i].u,&ee[i].v,&ee[i].w);
    44         ee[i].no=i;
    45     }
    46     sort(ee+1,ee+1+m,cmp);
    47     for(int i=1;i<=n;++i)f[i]=i;
    48     int tj=0;
    49     for(int i=1;i<=m;++i)
    50     {
    51         int u=ee[i].u,v=ee[i].v;
    52         if(find(f,u)!=find(f,v))
    53         {
    54             addage(u,v,ee[i].w,ee[i].no);
    55             addage(v,u,ee[i].w,ee[i].no);
    56             mxt+=ee[i].w;
    57             intr[ee[i].no]=1;
    58             u=find(f,u),v=find(f,v);
    59             f[u]=v;
    60             tj++;
    61             if(tj==n-1)break;
    62         }
    63     }
    64     dfs(1,0);
    65     for(int i=1;i<=m;++i)
    66     {
    67         int no=ee[i].no;
    68         if(intr[no]==0)
    69         {
    70             ans[no]=mxt;
    71             int u=ee[i].u,v=ee[i].v;
    72             u=find(ff,u);v=find(ff,v);
    73             while(u!=v)
    74             {
    75                 if(dep[v]>dep[u])swap(u,v);
    76                 ans[upno[u]]=ee[i].w;
    77                 ff[u]=fa[u];u=find(ff,u);
    78             }
    79         }
    80     }
    81     for(int i=1;i<=m;++i)if(ans[ee[i].no])ans[ee[i].no]+=mxt-ee[i].w;
    82     scanf("%d",&q);
    83     for(int no,i=1;i<=q;++i)
    84     {
    85         scanf("%d",&no);
    86         if(tj!=n-1)
    87         {
    88             puts("Not connected");
    89             continue;
    90         }
    91         if(intr[no]==0)printf("%d
    ",mxt);
    92         else if(ans[no])printf("%d
    ",ans[no]);
    93         else puts("Not connected");
    94     }
    95     return 0;
    96 }
    View Code
  • 相关阅读:
    【小白的CFD之旅】14 实例反思
    【小白的CFD之旅】13 敲门实例【续3】
    【小白的CFD之旅】12 敲门实例【续2】
    【小白的CFD之旅】11 敲门实例【续】
    【小白的CFD之旅】10 敲门实例
    【小白的CFD之旅】09 初识FLUENT
    【小白的CFD之旅】08 CFD速成之道
    【小白的CFD之旅】07 CFD常识
    【小白的CFD之旅】06 流体力学基础
    软件工程-构建之法 理解C#一小段程序
  • 原文地址:https://www.cnblogs.com/gryzy/p/14686840.html
Copyright © 2011-2022 走看看