• 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 }
  • 相关阅读:
    字符串 高精度计算
    JAVA Socket编程 课堂作业
    图论 Floyd算法
    天梯赛题解 L1-049 天梯赛座位分配
    天梯赛题解 -L1-039 古风排版
    HDU 5558 后缀数组
    HDU 6194 后缀数组
    HDU 5769 后缀数组
    HDU 4691 后缀数组+RMQ
    HDU 4135 容斥原理
  • 原文地址:https://www.cnblogs.com/hehe54321/p/9289649.html
Copyright © 2020-2023  润新知