zoukankan      html  css  js  c++  java
  • tarjan 求点双边双

    点双

      1 #include<iostream>
      2 #include<cstdio>
      3 #include<bitset>
      4 #include<queue>
      5 #include<vector>
      6 using namespace std;
      7 const int N=100050,M=200020;
      8 int fr1[M*2],fr2[M*2],dfn[N],low[N],stack[N*2],fa[N*2][23],ans[N],c[N*2],s[N*2],d[N*2],du[N],rt,top,num,tp,cnt,tt,n,m;//注意这里存点双的数组要开两倍
      9 bool cut[N];
     10 vector<int>dcc[N];
     11 struct node{int fr,to,pr;}mo1[M*2],mo2[M*2];
     12 void add1(int x,int y)
     13 {
     14     mo1[++tt].fr=x;mo1[tt].to=y;
     15     mo1[tt].pr=fr1[x];fr1[x]=tt;
     16 }
     17 void add2(int x,int y)
     18 {
     19     mo2[++tp].fr=x;mo2[tp].to=y;
     20     mo2[tp].pr=fr2[x];fr2[x]=tp;
     21 }
     22 int rd()
     23 {
     24     char cc=getchar();
     25     int s=0,w=1;
     26     while(cc<'0'||cc>'9') {if(cc=='-') w=-1;cc=getchar();}
     27     while(cc>='0'&&cc<='9') s=(s<<3)+(s<<1)+cc-'0',cc=getchar();
     28     return s*w;
     29 }
     30 void tarjan(int x)
     31 {
     32     low[x]=dfn[x]=++num;
     33     stack[++top]=x;
     34     int son=0;
     35     if(x==rt&&fr1[x]==0)
     36     {
     37         dcc[++cnt].push_back(x);
     38         return;
     39     }
     40     for(int i=fr1[x];i;i=mo1[i].pr)
     41     {
     42         int y=mo1[i].to;
     43         if(!dfn[y])
     44         {
     45             tarjan(y);
     46             low[x]=min(low[x],low[y]);
     47             if(low[y]>=dfn[x])
     48             {
     49                 int z;son++;cnt++;
     50                 if(x!=rt||son>1) cut[x]=1;
     51                 do{
     52                     z=stack[top--];
     53                     dcc[cnt].push_back(z);
     54                 }while(y!=z);//理解:不能弹到x,因为x还要属于其他点双
     55                 dcc[cnt].push_back(x);
     56             }
     57         }
     58         else low[x]=min(low[x],dfn[y]);
     59     }
     60 }
     61 void predfs(int x)
     62 {
     63     for(int i=1;i<=20;i++) fa[x][i]=fa[fa[x][i-1]][i-1];
     64     for(int i=fr2[x];i;i=mo2[i].pr)
     65     {
     66         int to=mo2[i].to;
     67         if(to==fa[x][0]) continue;
     68         fa[to][0]=x;
     69         d[to]=d[x]+1;
     70         predfs(to);
     71     }
     72 }
     73 int LCA(int x,int y)
     74 {
     75     if(d[x]<d[y]) swap(x,y);
     76     for(int i=20;~i;i--)
     77         if(d[fa[x][i]]>=d[y]) x=fa[x][i];
     78     if(x==y) return x;
     79     for(int i=20;~i;i--)
     80         if(fa[x][i]!=fa[y][i])//板子一定要打对
     81             x=fa[x][i],y=fa[y][i];
     82     return fa[x][0];
     83 }
     84 void dfs(int x)
     85 {
     86     for(int i=fr2[x];i;i=mo2[i].pr)
     87     {
     88         int to=mo2[i].to;
     89         if(to==fa[x][0])continue;
     90         dfs(to);
     91         s[x]+=s[to];
     92     }
     93 }
     94 int main()
     95 {
     96     int q;
     97     n=rd();m=rd();q=rd();
     98     for(int i=1,x,y;i<=m;i++)
     99     {
    100         x=rd(),y=rd();
    101         add1(x,y);add1(y,x);
    102     }
    103     for(int i=1;i<=n;i++) if(!dfn[i]) rt=i,tarjan(i);
    104     num=cnt;
    105     for(int i=1;i<=n;i++) if(cut[i]) c[i]=++num;//这就是为啥要开两倍,所有割点重新开
    106     for(int i=1;i<=cnt;i++)
    107         for(int j=0;j<dcc[i].size();j++)
    108         {
    109             int x=dcc[i][j];
    110             if(cut[x]) add2(i,c[x]),add2(c[x],i);
    111             else c[x]=i;
    112         }
    113     d[1]=1;predfs(1);
    114     for(int i=1,x,y,lca;i<=q;i++)
    115     {
    116         x=rd();y=rd();
    117         if(!cut[x])ans[x]++;
    118         if(!cut[y])ans[y]++;
    119         if(c[x]==c[y]) continue;
    120         x=c[x];y=c[y];lca=LCA(x,y);
    121         s[x]++,s[y]++,s[lca]--,s[fa[lca][0]]--;
    122     }
    123     dfs(1);
    124     for(int i=1;i<=n;i++)
    125         if(cut[i]) ans[i]=s[c[i]];
    126     for(int i=1;i<=n;i++)
    127         printf("%d
    ",ans[i]);
    128 }

    边双

    #include<iostream>
    #include<cstdio>
    #include<bitset>
    #include<queue>
    #include<vector>
    using namespace std;
    const int N=10050,M=20020;
    int fr[M*2],ft[M*2],dfn[N],low[N],stack[N],c[N],du[N],rt,top,num,dcc,cnt,tt=1,n,m;//从1开始编
    bool ins[N],ed[M];
    struct node{int fr,to,pr;}mo[M*2],no[M*2];
    void add(int x,int y)
    {
        mo[++tt].fr=x;mo[tt].to=y;
        mo[tt].pr=fr[x];fr[x]=tt;
    }
    int rd()
    {
        char cc=getchar();
        int s=0,w=1;
        while(cc<'0'||cc>'9') {if(cc=='-') w=-1;cc-getchar();}
        while(cc>='0'&&cc<='9') s=(s<<3)+(s<<1)+cc-'0',cc=getchar();
        return s*w;
    }
    void tarjan(int x,int id)
    {
        low[x]=dfn[x]=++num;
        for(int i=fr[x];i;i=mo[i].pr)
        {
            int y=mo[i].to;
            if(!dfn[y])
            {
                tarjan(y,i);
                low[x]=min(low[x],low[y]);
                if(low[y]>dfn[x])
                    ed[i]=ed[i^1]=1;//0,1 |2,3 |4,5配对,因此一定要从1开始编号
            }
            else if(i!=(id^1)) low[x]=min(low[x],dfn[y]);
        }
    }
    void dfs(int x)
    {
        c[x]=dcc;
        for(int i=fr[x];i;i=mo[i].pr)
        {
            int y=mo[i].to;
            if(c[y]||ed[i]) continue;
            dfs(y);
        }
    }
    int main()
    {
        n=rd();m=rd();
        for(int i=1,x,y;i<=m;i++)
        {
            x=rd(),y=rd();
            add(x,y);add(y,x);
        }
        for(int i=1;i<=n;i++) if(!dfn[i]) tarjan(i,0);
        for(int i=1;i<=n;i++) if(!c[i]) ++dcc,dfs(i);//dfs重新搜边双
        for(int i=2;i<=tt;i++)
        {
            int x=mo[i].fr,y=mo[i].to;
            if(c[x]==c[y]) continue;
            du[c[y]]++;
        }
        int ans=1;
        for(int i=1;i<=dcc;i++) if(du[i]==1) ans++;
        printf("%d
    ",ans>>1);
    }
    /*
    g++ 1.cpp -o 1
    ./1
    7 7
    1 2
    2 3
    3 4
    2 5
    4 5
    5 6
    5 7
    */
    Zeit und Raum trennen dich und mich.时空将你我分开。
  • 相关阅读:
    Ubuntu 14.04 LTS 系统空间不足,输入密码后,无法进入桌面的解决办法
    语言代码表
    在WPS中删除整行的快捷键是什么?
    Google浏览器&插件
    Linux命令大全
    Python下载安装
    Tiobe最新编程语言排行
    windows 清理利器
    如何用VBA实现格式刷的功能?
    武侠音乐精装
  • 原文地址:https://www.cnblogs.com/starsing/p/11182986.html
Copyright © 2011-2022 走看看