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\n",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\n",ans>>1);
}
/*
g++ 1.cpp -o 1
./1
7 7
1 2
2 3
3 4
2 5
4 5
5 6
5 7
*/

 

posted @ 2019-07-14 06:41  starsing  阅读(524)  评论(0编辑  收藏  举报