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
    越努力 越幸运
  • 相关阅读:
    解决SharePoint 文档库itemadded eventhandler导致的上传完成后,编辑页面保持报错的问题,错误信息为“该文档已经被编辑过 the file has been modified by...”
    解决SharePoint 2013 designer workflow 在发布的报错“负载平衡没有设置”The workflow files were saved but cannot be run.
    随机实例,随机值
    Spring4笔记
    struts2笔记(3)
    struts2笔记(2)
    获取文本的编码类型(from logparse)
    FileUtil(from logparser)
    DateUtil(SimpleDateFormat)
    struts2笔记
  • 原文地址:https://www.cnblogs.com/OI-zzyy/p/11183044.html
Copyright © 2011-2022 走看看