Pursuit For Artifacts CodeForces

https://vjudge.net/problem/CodeForces-652E

边双啊,就是点双那个tarjan里面,如果low[v]==dfn[v](等同于low[v]>dfn[u]),表示v及其子节点只能访问到v本身,不能访问到v的祖先,那么边(u,v)是一条桥

然后再dfs一遍,不经过桥,每一次dfs得到的连通块就是一个边双。可以把一个边双缩成一个点,各个边双之间就由桥相连,得到一棵树

对于此题,可以发现,如果在一个边双内有两点a,b,还有一条边(c,d),那么一定存在一条路径从a到c经(c,d)到d再到b(不经过重复边)(好证,不证了)upd:突然发现上面那个根本就不好证明..

证明(改编自https://codeforces.com/blog/entry/14832,那个是点双的类似结论):

建一张新的网络流图。用(u,v,w)表示从u到v流量上限为w的边。

对原边双中每一条边(u,v)建新边(u,v,1),(v,u,1)。建新点S,T,建边(S,c,1),(S,d,1),(a,T,1),(b,T,1)

显然此时如果S到T的最大流是2,那么就存在要求的路径。

最大流=最小割,显然最小割是2

因此,只要一个边双内存在一条边有宝物,那么就存在不重复经过边的路径,从边双内给定点开始,到达边双内另一给定点,且拿到宝物

缩点成树后dfs即可

错误记录:

1.67行后多了一个反向加边;事实上由于70-74行的特殊写法,只要加一个方向的边即可

2.83行少了"|ok[u]"

  1 #include<cstdio>
  2 #include<algorithm>
  3 #include<cstring>
  4 #include<vector>
  5 using namespace std;
  6 #define fi first
  7 #define se second
  8 #define mp make_pair
  9 #define pb push_back
 10 typedef long long ll;
 11 typedef unsigned long long ull;
 12 typedef pair<int,int> pii;
 13 #define N 300100
 14 #define M 300100
 15 struct E{int to,nxt;bool d;};
 16 namespace G
 17 {
 18 E e[M<<1];
 19 int f1[N],ne=1;
 20 int dfn[N],dfc;
 21 bool bri[M];
 22 void me(int a,int b,int c)
 23 {
 24     e[++ne].to=b;e[ne].nxt=f1[a];f1[a]=ne;e[ne].d=c;
 25     e[++ne].to=a;e[ne].nxt=f1[b];f1[b]=ne;e[ne].d=c;
 26 }
 27 int dfs(int u,int last)
 28 {
 29     int lowu=dfn[u]=++dfc,v,lowv;
 30     for(int k=f1[u];k;k=e[k].nxt)
 31     {
 32         v=e[k].to;
 33         if(!dfn[v])
 34         {
 35             lowv=dfs(v,k);
 36             lowu=min(lowu,lowv);
 37             if(lowv>dfn[u])    bri[k/2]=1;
 38         }
 39         else if(dfn[v]<dfn[u]&&k!=(last^1))
 40             lowu=min(lowu,dfn[v]);
 41     }
 42     return lowu;
 43 }
 44 int now;
 45 int eccno[N],cnt,d[N];
 46 bool vis[N];
 47 void dfs2(int u)
 48 {
 49     eccno[u]=cnt;vis[u]=1;
 50     for(int k=f1[u];k;k=e[k].nxt)
 51         if(!bri[k/2])
 52         {
 53             d[cnt]|=e[k].d;
 54             if(!vis[e[k].to])    dfs2(e[k].to);
 55         }
 56 }
 57 }
 58 int n,m;
 59 namespace T
 60 {
 61 using G::eccno;using G::d;
 62 E e[N<<1];
 63 int f1[N],ne=1;
 64 void me(int a,int b,int c)
 65 {
 66     e[++ne].to=b;e[ne].nxt=f1[a];f1[a]=ne;e[ne].d=c;
 67 }
 68 void build()
 69 {
 70     int i,k;
 71     for(i=1;i<=n;i++)
 72         for(k=G::f1[i];k;k=G::e[k].nxt)
 73             if(G::bri[k/2])
 74                 me(eccno[i],eccno[G::e[k].to],G::e[k].d);
 75 }
 76 bool ok[N];
 77 void dfs(int u,int fa)
 78 {
 79     ok[u]|=d[u];
 80     for(int k=f1[u];k;k=e[k].nxt)
 81         if(e[k].to!=fa)
 82         {
 83             ok[e[k].to]|=(e[k].d|ok[u]);
 84             dfs(e[k].to,u);
 85         }
 86 }
 87 }
 88 int main()
 89 {
 90     int i,a,b,c;
 91     scanf("%d%d",&n,&m);
 92     for(i=1;i<=m;i++)    scanf("%d%d%d",&a,&b,&c),G::me(a,b,c);
 93     G::dfs(1,-1);
 94     for(i=1;i<=n;i++)    if(!G::vis[i])    ++G::cnt,G::dfs2(i);
 95     T::build();
 96     scanf("%d%d",&a,&b);
 97     T::dfs(G::eccno[a],0);
 98     puts(T::ok[G::eccno[b]]?"YES":"NO");
 99     return 0;
100 }
原文地址:https://www.cnblogs.com/hehe54321/p/9289649.html