【NOIP模拟考三】无向图的桥 day1 second 荒岛野人

题目描述

输入

输出

样例输入

 (如果复制到控制台无换行,可以先粘贴到文本编辑器,再复制)

8 7
3 4
1 2
2 3
3 1
3 6
4 5
7 8
1 1
0 0
0 0
0 1
1 0
1 0
1 0
0 1

样例输出

3
0
0
0
2
2
1

提示

    迎接FFF团的胜利!

    第二题也许算是很简单的了。人家图的边名字都取成桥了你怎么能不做成桥呢……是吧……

    对于一条边,如果不是桥(即炸毁它不会发生图的断裂),则它的答案为0(显然)。否则呢~则为分开的两部分男女数量互相乘再加起来(如两部分男女数量:land1-boy10 girl9 land2-boy7 girl8,可以摧毁10*8+9*7=143对情侣),这可以用一个简单的size数组来解决。

    那么求出桥的方法就是tarjan的时间戳了……没有什么讲的必要……

    PS:尽管题目口口声声说没有重边,数据也一改再改,但它就是有重边=_=|||……然而标称却没有判重……尬……导致我判了重的代码WA了……O__O"

    代码:

    1.这是不判重的(判断可走不可走只看是否是父亲)

//%>_<% ~(>_<)~ 
#include<cmath> 
#include<cstdio> 
#include<cstring> 
#include<algorithm> 
using namespace std; 
#define N 100005 
#define M 1000005 
#define ll long long 
int n,m; 
ll boy[N],girl[N]; 
int fir[N],t[M],nex[M],cnt=1; 
int tim,dfn[N],low[N]; 
bool root[N],bdg[M],vis[N]; 
ll FFF[M]; 
void add(int a,int b) 
{ 
    cnt++; 
    t[cnt]=b; 
    nex[cnt]=fir[a]; 
    fir[a]=cnt; 
} 
void dfs(int r,int fa) 
{ 
    dfn[r]=low[r]=++tim; 
    for(int i=fir[r];i;i=nex[i]) 
    { 
        int v=t[i]; 
        if(v!=fa) 
        { 
            if(dfn[v]) 
                low[r]=min(low[r],dfn[v]); 
            else
            { 
                dfs(v,r); 
                boy[r]+=boy[v]; 
                girl[r]+=girl[v]; 
                if(low[v]>dfn[r]) 
                    bdg[i]=bdg[i^1]=1; 
                else
                    low[r]=min(low[r],low[v]); 
            } 
        } 
    } 
} 
int allboy,allgirl; 
void dfs2(int r) 
{ 
    vis[r]=1; 
    for(int i=fir[r];i;i=nex[i]) 
    { 
        int v=t[i]; 
        if(!vis[v]) 
        { 
            if(bdg[i]) 
                FFF[i]=FFF[i^1]=(allboy-boy[v])*girl[v]+(allgirl-girl[v])*boy[v]; 
            dfs2(v); 
        } 
    } 
} 
int main() 
{ 
    scanf("%d%d",&n,&m); 
    for(int i=1;i<=m;i++) 
    { 
        int a,b; 
        scanf("%d%d",&a,&b); 
        add(a,b); 
        add(b,a); 
    } 
    for(int i=1;i<=n;i++) 
        scanf("%lld%lld",&boy[i],&girl[i]); 
    for(int i=1;i<=n;i++) 
    { 
        if(!dfn[i]) 
        { 
            root[i]=1; 
            dfs(i,0); 
        } 
    } 
    for(int i=1;i<=n;i++) 
        if(root[i]) 
            allboy=boy[i],allgirl=girl[i],dfs2(i); 
    for(int i=1;i<=m;i++) 
        printf("%lld\n",FFF[2*i]); 
} 
    2.然后这是判了重的(判断能不能走到不再判断是否是父亲,而是判断是否是来时的边的反向边)

//%>_<% ~(>_<)~ 
#include<cmath> 
#include<cstdio> 
#include<cstring> 
#include<algorithm> 
using namespace std; 
#define N 100005 
#define M 1000005 
#define ll long long 
int n,m; 
ll boy[N],girl[N]; 
int fir[N],t[M],nex[M],cnt=1; 
int tim,dfn[N],low[N]; 
bool root[N],bdg[M],vis[N]; 
ll FFF[M]; 
void add(int a,int b) 
{ 
    cnt++; 
    t[cnt]=b; 
    nex[cnt]=fir[a]; 
    fir[a]=cnt; 
} 
void dfs(int r,int fr) 
{ 
    dfn[r]=low[r]=++tim; 
    for(int i=fir[r];i;i=nex[i]) 
    { 
        int v=t[i]; 
        if((i^1)!=fr) 
        { 
            if(dfn[v]) 
                low[r]=min(low[r],dfn[v]); 
            else
            { 
                dfs(v,i); 
                boy[r]+=boy[v]; 
                girl[r]+=girl[v]; 
                if(low[v]>dfn[r]) 
                    bdg[i]=bdg[i^1]=1; 
                else
                    low[r]=min(low[r],low[v]); 
            } 
        } 
    } 
} 
int allboy,allgirl; 
void dfs2(int r) 
{ 
    vis[r]=1; 
    for(int i=fir[r];i;i=nex[i]) 
    { 
        int v=t[i]; 
        if(!vis[v]) 
        { 
            if(bdg[i]) 
                FFF[i]=FFF[i^1]=(allboy-boy[v])*girl[v]+(allgirl-girl[v])*boy[v]; 
            dfs2(v); 
        } 
    } 
} 
int main() 
{ 
    scanf("%d%d",&n,&m); 
    for(int i=1;i<=m;i++) 
    { 
        int a,b; 
        scanf("%d%d",&a,&b); 
        add(a,b); 
        add(b,a); 
    } 
    for(int i=1;i<=n;i++) 
        scanf("%lld%lld",&boy[i],&girl[i]); 
    for(int i=1;i<=n;i++) 
    { 
        if(!dfn[i]) 
        { 
            root[i]=1; 
            dfs(i,0); 
        } 
    } 
    for(int i=1;i<=n;i++) 
        if(root[i]) 
            allboy=boy[i],allgirl=girl[i],dfs2(i); 
    for(int i=1;i<=m;i++) 
        printf("%lld\n",FFF[2*i]); 
} 


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值