codeforces 652E Pursuit For Artifacts 边双连通分量

题意:n个点,m条边的无向图,有的边上有标记,每条边只能走一次

        给你一个起点,一个终点,询问是否能找到从起点到终点的路径,这条路径至少包含一条含有标记的边

分析:然后边双缩点

下面介绍一下边双的性质

1,删掉边双内任意一条边,不影响边双的连通性

2,任取边双内两个点u,v,对于边双里面的任意一条边,至少包含于一条u到v的路径

 

所以对于这个题,可以运用上述的第二个性质,对于在边双里的标记边,都是可以经过的

然后缩点以后,变成一棵树,然后从起点所在的边双开始遍历,找到到终点所在边双的路径,询问权值是否大于0就行了

注意一点:这里的权值是点权加边权

#include <iostream>
#include <cstdio>
#include <cstring>
#include <stack>
using namespace std;
const int N=3e5+5;
int n,m,s,t;
struct Edge
{
    int u,v,w,next;
} edge[N<<1],e[N<<1];
int head[N],tot,h[N];
void add(int u,int v,int w)
{
    edge[tot].u=u;
    edge[tot].v=v;
    edge[tot].w=w;
    edge[tot].next=head[u];
    head[u]=tot++;
}
void adde(int u,int v,int w)
{
    e[tot].v=v;
    e[tot].w=w;
    e[tot].next=h[u];
    h[u]=tot++;
}
int pre[N],low[N],clk,bcc,bel[N];
stack<int>S;
void targin(int u,int f)
{
    pre[u]=low[u]=++clk;
    S.push(u);
    for(int i=head[u]; ~i; i=edge[i].next)
    {
        int v=edge[i].v;
        if(v==f)continue;
        if(!pre[v])
        {
            targin(v,u);
            low[u]=min(low[v],low[u]);
        }
        else low[u]=min(pre[v],low[u]);
    }
    if(pre[u]==low[u])
    {
        ++bcc;
        int k;
        do
        {
            k=S.top();
            S.pop();
            bel[k]=bcc;
        }
        while(k!=u);
    }
}
int val[N];
bool get(int u,int f,int sum)
{
    sum+=val[u];
    if(u==t)return sum;
    for(int i=h[u]; ~i; i=e[i].next)
    {
        int v=e[i].v;
        if(v==f)continue;
        if(get(v,u,sum+e[i].w))return true;
    }
    return false;
}
int main()
{
    scanf("%d%d",&n,&m);
    memset(head,-1,sizeof(head));
    int tmp=0;
    for(int i=1; i<=m; ++i)
    {
        int u,v,w;
        scanf("%d%d%d",&u,&v,&w),tmp+=w;
        add(u,v,w),add(v,u,w);
    }
    scanf("%d%d",&s,&t);
    if(tmp==0)
    {
        printf("NO\n");
        return 0;
    }
    targin(s,-1);
    tmp=tot;
    memset(h,-1,sizeof(h)),tot=0;
    for(int i=0; i<tmp; i=i+2)
    {
        int u=edge[i].u,v=edge[i].v;
        u=bel[u],v=bel[v];
        if(u==v)val[u]+=edge[i].w;
        else adde(u,v,edge[i].w),adde(v,u,edge[i].w);
    }
    s=bel[s];
    t=bel[t];
    if(get(s,-1,0))printf("YES\n");
    else printf("NO\n");
    return 0;
}
View Code

 

 

 

       

转载于:https://www.cnblogs.com/shuguangzw/p/5326435.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值