zoukankan      html  css  js  c++  java
  • [hdu6990]Directed Minimum Spanning Tree

    模板题:在有向图中,对每一个点求以其为根的最小(外向)生成树

    (当图是强连通时)可以使用朱刘算法,算法过程如下:

    1.对每一个节点,选择指向该点的边权最小的边,即得到一张子图

    2.任选这张子图的一个简单环,并对这个环执行以下操作——

    (1)对于环上的边$(u,v)$​,将所有以$v$​为终点的边边权减去$(u,v)$​​的边权

    (2)新建一个点为将环上所有点合并后的结果,并删除新点的自环

    3.重复此过程,直至仅剩下一个点

    (不难证明第1步中每一个点入度都非0,第2步中一定存在一个环)

    在此过程中,再另外维护一棵树:在第2.(2)中,环上的每一个点向新建的点连一条边权为其对应边(即环上指向该点的边)的边权的边,显然这是一棵内向树,且根即为最后剩下的节点

    此时,每一个节点的答案即树上的边权和-其到根路径上的边权和

    下面,问题即如何(快速)实现之前的过程——

    先对每一个点的边集(指到该点的边)维护一个可并堆,显然即可支持1的查询和2.(2)的合并,2.(1)的修改也可以用懒标记实现

    此时,考虑从任意一点dfs,由于每一个点入度都非0,那么不断选择"指向自己的边权最小的边",当重复访问一个节点时即可进行缩点,缩点后继续递归即可

    另外,图并不一定强连通,这个问题可以通过加入边$(1,2,infty),(2,3,infty),...,(n,1,infty)$​来解决,若最终某个点的答案为$infty$​​​​即说明不存在以该点为根的生成树,进而图即变为强连通的

    综上,总复杂度为$o(nlog n)$​,可以通过

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 #define N 200005
     4 #define ll long long
     5 #define ull unsigned ll
     6 #define pil pair<int,ll>
     7 #define fi first
     8 #define se second
     9 vector<int>v[N<<1];
    10 int V,t,n,m,x,y,z,rt[N],ls[N<<1],rs[N<<1],fa[N],st[N],vis[N];
    11 ll tag[N<<1],Val[N];
    12 ull ans[N];
    13 pil val[N<<1],pos[N];
    14 int find(int k){
    15     if (k==fa[k])return k;
    16     return fa[k]=find(fa[k]);
    17 }
    18 void upd(int k,ll x){
    19     tag[k]+=x,val[k].se+=x;
    20 }
    21 void down(int k){
    22     if (!tag[k])return;
    23     if (ls[k])upd(ls[k],tag[k]);
    24     if (rs[k])upd(rs[k],tag[k]);
    25     tag[k]=0;
    26 }
    27 int New(int x,ll z){
    28     int k=++V;
    29     ls[k]=rs[k]=tag[k]=0;
    30     val[k]=make_pair(x,z); 
    31     return V;
    32 }
    33 int merge(int k1,int k2){
    34     if ((!k1)||(!k2))return k1+k2;
    35     if (val[k1].se>val[k2].se)swap(k1,k2);
    36     down(k1);
    37     rs[k1]=merge(rs[k1],k2);
    38     swap(ls[k1],rs[k1]);
    39     return k1;
    40 }
    41 void add(int x,int y,ll z){
    42     rt[y]=merge(rt[y],New(x,z));
    43 }
    44 void del(int x){
    45     down(rt[x]);
    46     rt[x]=merge(ls[rt[x]],rs[rt[x]]);
    47 }
    48 void dfs(int x,ull s){
    49     if (x<=n)ans[x]=s;
    50     for(int i=0;i<v[x].size();i++)dfs(v[x][i],s-Val[v[x][i]]);
    51 }
    52 int main(){
    53     scanf("%d",&t);
    54     while (t--){
    55         scanf("%d%d",&n,&m);
    56         V=st[0]=ans[0]=0;
    57         for(int i=1;i<=(n<<1);i++){
    58             fa[i]=i;
    59             rt[i]=vis[i]=0;
    60             v[i].clear();
    61         }
    62         for(int i=1;i<=m;i++){
    63             scanf("%d%d%d",&x,&y,&z);
    64             add(x,y,z);
    65         }
    66         for(int i=1;i<=n;i++)add(i,i%n+1,1e14);
    67         st[++st[0]]=1,vis[1]=1;
    68         int nn=n;
    69         while (1){
    70             x=st[st[0]];
    71             while ((rt[x])&&(find(val[rt[x]].fi)==x))del(x);
    72             if (!rt[x])break;
    73             y=find(val[rt[x]].fi);
    74             Val[x]=val[rt[x]].se,del(x);
    75             if (rt[x])upd(rt[x],-Val[x]);
    76             if (!vis[y]){
    77                 st[++st[0]]=y,vis[y]=1;
    78                 continue;
    79             }
    80             nn++;
    81             while (1){
    82                 v[nn].push_back(x);
    83                 fa[x]=nn,rt[nn]=merge(rt[nn],rt[x]);
    84                 if (x==y){
    85                     st[st[0]]=nn,vis[nn]=1;
    86                     break;
    87                 }
    88                 x=st[--st[0]];
    89             }
    90         }
    91         for(int i=1;i<nn;i++)ans[0]+=Val[i];
    92         dfs(nn,ans[0]);
    93         for(int i=1;i<=n;i++){
    94             if (ans[i]>1e14)printf("-1
    ");
    95             else printf("%llu
    ",ans[i]);
    96         }
    97     }
    98     return 0;
    99 } 
    View Code
  • 相关阅读:
    linux 分析 目标文件 的命令
    bss,data,text,rodata,堆,栈,常量段
    Linux进程地址空间详解
    机器周期,指令周期,时钟周期,节拍与晶振
    银行家算法——C语言(11计科1班-孙鹏启——修正)
    bash —— bind ( 一个功能强大的组合键! Alt + . )
    【5002】排版问题
    【?】【7007】栈、模拟
    【u235】背单词
    【t076】竞赛排名
  • 原文地址:https://www.cnblogs.com/PYWBKTDA/p/15150926.html
Copyright © 2011-2022 走看看