zoukankan      html  css  js  c++  java
  • [bzoj3331] [BeiJing2013] 压力(tarjan 点双连通分量)

    题干:

      这世界上有N个网络设备,他们之间有M个双向的链接。这个世界是连通的。在一段时间里,有Q个数据包要从一个网络设备发送到另一个网络设备。一个网络设备承受的压力有多大呢?很显然,这取决于Q个数据包各自走的路径。不过,某些数据包无论走什么路径都不可避免的要通过某些网络设备。你要计算:对每个网络设备,必须通过(包括起点、终点)他的数据包有多少个?

      对于40%的数据,N,M,Q≤2000
      对于60%的数据,N,M,Q≤40000
      对于100%的数据,N≤100000,M,Q≤200000

    题解:

      必须通过的路径?很容易就可以想到树上差分求解(在路径上都放一个价值为1的物品,答案就是每个点物品的总价值)。

      但题干中并没有说这一定是一棵树,只是说是连通图。

      那我们就需考虑几种情况:

      1、起始节点与末尾节点都为割点:直接在起始节点与末尾节点差分

        (怎么来的割点?不是走路径吗?其实我们差分的对象是几个点,针对于点,我们就应该想到点双连通分量

      2、起始节点与末尾节点有一个不为割点或都不为割点:

        这就需要先找出起始节点或末尾节点所在环的割点,再在这个割点上进行差分。

        (直接差分不行吗?题干中说的是“ 必须通过它的数据包有多少个 ”,若一个点在环上,那么它一定至少有两条路径可以走,就不满足“ 必须 ”这个条件)

      考虑了这两种情况,这道题就有了一个比较完整的框架。但在真正解题时,我们采用缩点的方法来等效于上述

    “找出起始节点或末尾节点所在环的割点,再在这个割点上进行差分”

      (在最后的统计答案中,dfs序还是比较好用,省去了跑dfs统计答案)

      tarjan 点双连通分量求法+缩点:

     1         if(!dfn[to]){
     2             tarjan(to);
     3             low[x]=min(low[x],low[to]);
     4             if(low[to]>=dfn[x]){
     5                 opt++; sum++;
     6                 if(x!=1||opt>1) cut[x]=1;
     7                 do{
     8                     tmp=sta[up--];
     9                     cir[tmp]=sum;
    10                     dcc[sum].push_back(tmp);
    11                 }while(tmp!=to);
    12                 cir[x]=sum;
    13                 dcc[sum].push_back(x);
    14             }
    15         }
    16         else low[x]=min(low[x],dfn[to]);    

    Code:(两种不同打法,第二种为正解,第一种打得较方便,但时间复杂度会高一些)

     1 #include<cstdio>
     2 #include<cstring>
     3 #include<queue>
     4 #include<iostream>
     5 #define $ 220010
     6 using namespace std;
     7 int m,n,q,first[$],tot1,dfn[$],low[$],tar,tip[$],second[$],tot2;
     8 int dad[$][22],sta[$],up,ans[$],dep[$],sum,pre[$];
     9 struct tree{    int to,next;    }a[$*5],tr[$*5];
    10 inline int min(int x,int y)    {    return x<y?x:y;    }
    11 inline void swap(int &x,int &y){    int t=x; x=y; y=t;    }
    12 inline void add(int x,int y){    
    13     a[++tot1]=(tree){    y,first[x]    };
    14     first[x]=tot1;
    15     a[++tot1]=(tree){    x,first[y]    };
    16     first[y]=tot1;
    17 }
    18 inline void addtr(int x,int y){
    19     tr[++tot2]=(tree){    y,second[x]    };
    20     second[x]=tot2;
    21     tr[++tot2]=(tree){    x,second[y]    };
    22     second[y]=tot2;
    23 }
    24 inline void tarjan(int x){
    25     dfn[x]=low[x]=++tar;  sta[++up]=x;
    26     for(register int i=first[x],tmp;i;i=a[i].next){
    27         int to=a[i].to;
    28         if(!dfn[to]){
    29             tarjan(to);
    30             low[x]=min(low[x],low[to]);
    31             if(low[to]>=dfn[x]){
    32                 ++sum;
    33                 do{
    34                     tmp=sta[up--];
    35                     addtr(sum,tmp);
    36                 }while(tmp!=to);
    37                 addtr(sum,x);
    38             }
    39         }
    40         else low[x]=min(low[x],dfn[to]);
    41     }
    42 }
    43 inline void ready(int x){
    44     pre[--pre[0]]=x;
    45     for(register int i=second[x];i;i=tr[i].next){
    46         int to=tr[i].to;
    47         if(to==dad[x][0]) continue;
    48         dad[to][0]=x;
    49         for(register int j=1;j<=20;++j) dad[to][j]=dad[dad[to][j-1]][j-1];
    50         dep[to]=dep[x]+1;
    51         ready(to);
    52     }
    53 }
    54 inline int LCA(int x,int y){
    55     if(dep[x]<dep[y]) swap(x,y);
    56     for(register int i=20;i>=0;--i)
    57         if(dep[dad[x][i]]>=dep[y]) x=dad[x][i];
    58     if(x==y) return x;
    59     for(register int i=20;i>=0;--i)
    60         if(dad[x][i]!=dad[y][i]) x=dad[x][i],y=dad[y][i];
    61     return dad[x][0];
    62 }
    63 signed main(){
    64     scanf("%d%d%d",&n,&m,&q); sum=n;
    65     for(register int i=1,x,y;i<=m;++i) scanf("%d%d",&x,&y),add(x,y);
    66     tarjan(1);
    67     pre[0]=sum+1; dep[1]=1;
    68     ready(1);
    69     for(register int i=1,x,y,lca;i<=q;++i){
    70         scanf("%d%d",&x,&y);  lca=LCA(x,y);
    71         ++ans[x];   ++ans[y];
    72         --ans[lca]; --ans[dad[lca][0]];
    73     }
    74     for(register int i=1,x;i<=sum;++i)
    75          x=pre[i],ans[dad[x][0]]+=ans[x];
    76     for(register int i=1;i<=n;++i) printf("%d
    ",ans[i]);
    77 }
    View Code
     1 #include<cstdio>
     2 #include<cstring>
     3 #include<queue>
     4 #include<vector>
     5 #define $ 220010
     6 using namespace std;
     7 int m,n,q,first[$],tot1,dfn[$],low[$],tar,tip[$],second[$],tot2,cut[$],cnt;
     8 int dad[$*2][22],sta[$],up,ans[$],dep[$],sum,pre[$],cir[$],id[$],data[$];
     9 vector<int> dcc[$];
    10 struct tree{    int to,next;    }a[$*5],tr[$*5];
    11 inline int min(int x,int y)    {    return x<y?x:y;    }
    12 inline void swap(int &x,int &y){    int t=x; x=y; y=t;    }
    13 inline void add(int x,int y){    
    14     a[++tot1]=(tree){    y,first[x]    };
    15     first[x]=tot1;
    16     a[++tot1]=(tree){    x,first[y]    };
    17     first[y]=tot1;
    18 }
    19 inline void addtr(int x,int y){
    20     tr[++tot2]=(tree){    y,second[x]    };
    21     second[x]=tot2;
    22     tr[++tot2]=(tree){    x,second[y]    };
    23     second[y]=tot2;
    24 }
    25 inline void tarjan(int x,int opt=0){
    26     dfn[x]=low[x]=++tar;  sta[++up]=x;
    27     for(register int i=first[x],tmp;i;i=a[i].next){
    28         int to=a[i].to;
    29         if(!dfn[to]){
    30             tarjan(to);
    31             low[x]=min(low[x],low[to]);
    32             if(low[to]>=dfn[x]){
    33                 opt++; sum++;
    34                 if(x!=1||opt>1) cut[x]=1;
    35                 do{
    36                     tmp=sta[up--];
    37                     cir[tmp]=sum;
    38                     dcc[sum].push_back(tmp);
    39                 }while(tmp!=to);
    40                 cir[x]=sum;
    41                 dcc[sum].push_back(x);
    42             }
    43         }
    44         else low[x]=min(low[x],dfn[to]);
    45     }
    46 }
    47 inline void ready(int x){
    48     pre[--pre[0]]=x;
    49     for(register int i=second[x];i;i=tr[i].next){
    50         int to=tr[i].to;
    51         if(to==dad[x][0]) continue;
    52         dad[to][0]=x;
    53         for(register int j=1;j<=20;++j) dad[to][j]=dad[dad[to][j-1]][j-1];
    54         dep[to]=dep[x]+1;
    55         ready(to);
    56     }
    57 }
    58 inline int LCA(int x,int y){
    59     if(dep[x]<dep[y]) swap(x,y);
    60     for(register int i=20;i>=0;--i)
    61         if(dep[dad[x][i]]>=dep[y]) x=dad[x][i];
    62     if(x==y) return x;
    63     for(register int i=20;i>=0;--i)
    64         if(dad[x][i]!=dad[y][i]) x=dad[x][i],y=dad[y][i];
    65     return dad[x][0];
    66 }
    67 signed main(){
    68     scanf("%d%d%d",&n,&m,&q); cnt=n;
    69     for(register int i=1,x,y;i<=m;++i) scanf("%d%d",&x,&y),add(x,y);
    70     tarjan(1);
    71     for(register int i=1;i<=n;++i) if(cut[i]) cir[i]=id[i]=++cnt;
    72     for(register int i=1;i<=sum;++i)
    73         for(register int j=0;j<dcc[i].size();++j){
    74             int to=dcc[i][j];
    75             if(cut[to]) addtr(i,id[to]);
    76         }
    77     pre[0]=cnt+1; dep[1]=1;
    78     ready(1);
    79     for(register int i=1,x,y,lca;i<=q;++i){
    80         scanf("%d%d",&x,&y);  
    81         if(!cut[x]) data[x]++;
    82         if(!cut[y]) data[y]++;
    83         x=cir[x], y=cir[y]; 
    84         lca=LCA(x,y);
    85         ++ans[x];   ++ans[y];
    86         --ans[lca]; --ans[dad[lca][0]];
    87     }
    88     for(register int i=1,x;i<=cnt;++i)
    89          x=pre[i],ans[dad[x][0]]+=ans[x];
    90     for(register int i=1;i<=n;++i) printf("%d
    ",cut[i]?ans[cir[i]]:data[i]);
    91 }
    View Code
    越努力 越幸运
  • 相关阅读:
    MQTT---HiveMQ源代码具体解释(四)插件载入
    HTTP访问控制(CORS)
    java实现限流
    Orika的使用姿势,Orika java bean copy 框架
    uploadify是通过flash上传,服务器获取type为application/octet-stream
    ThinkPHP 5使用 Composer 组件名称可以从https://packagist.org/ 搜索到
    3种方法轻松处理php开发中emoji表情的问题
    解决thinkphp设置session周期无效的问题
    如何使用沙箱测试单笔转账到支付宝账号(php版) https://openclub.alipay.com/read.php?tid=1770&fid=28
    微信jssdk批量添加卡券接口
  • 原文地址:https://www.cnblogs.com/OI-zzyy/p/11183044.html
Copyright © 2011-2022 走看看