困难的图论

题意

给定由\(n\)个点\(m\)条边组成的无向连通图,保证没有重边和自环。
你需要找出所有边,满足这些边恰好存在于一个简单环中。一个环被称为简单环,当且仅当
它包含的所有点都只在这个环中被经过了一次。
注意到这些边可能有很多条,你只需要输出他们编号的异或和即可。

思路

可以先从图中dfs出一棵生成树
可知任一简单环一定包含一条非树边
把玩样例可以发现,若一条边存在于一个简单环中,当且仅当它满足如下两个条件之一:

  • 此边为非树边,且它覆盖的树边不和任何其他非树边覆盖的树边有公共边
  • 此边为树边,且覆盖它的非树边满足上述条件

于是我们可以对每一个非树边覆盖的树边进行链加,加完后枚举每一条非树边统计答案

具体实现

运用树上差分思想可以算出每条树边被多少条非树边覆盖,我们称它为\(val[i]\)
若此非树边所覆盖的树边的\(val[i]\)均为\(1\),则可以累加
那么如何判断和累加?可以用前缀来做(具体见代码)
(还有一个玄皮的性质:环上的点在生成树上形成一条链,因此不用求\(lca\)

注意事项

  • 建双向边
  • 注意顺序,不要同一个简单环加两次

不知为什么,交上去总是\(RE\)
最后受不了开挂

int size=40<<20;//40M
__asm__ ("movq %0,%%rsp\n"::"r"((char*)malloc(size)+size));//网站开栈

还发现一个有趣的东西:一般关于环的问题都要建出生成树,然后考虑树边与非树边的关系

code

#include<bits/stdc++.h>
using namespace std;
const int N=1e6+50000;
int n,m,tot,ans;
int fi[N],ne[N<<1],to[N<<1],w[N<<1];
int val[N],dep[N],s[N],asd[N];
bool pd[N];
inline int read()
{
    int s=0,w=1; char ch=getchar();
    for(;!isdigit(ch);ch=getchar())if(ch=='-')w=-1;
    for(;isdigit(ch);ch=getchar())s=(s<<1)+(s<<3)+(ch^48);
    return s*w;
}
inline void add(int x,int y,int s)
{
    ne[++tot]=fi[x],fi[x]=tot,to[tot]=y,w[tot]=s;
}
void dfs1(int x,int pr)
{
    dep[x]=dep[pr]+1;
    pd[x]=true;
    for(int i=fi[x];i;i=ne[i])
    {
        int v=to[i];
        if(v==pr) continue;
        if(pd[v])
        {
            if(dep[v]>dep[x]) continue;//顺序问题
            ++val[x],--val[v];
            continue;
        }
        dfs1(v,x);
    }
}
void dfs2(int x,int pr)
{
    pd[x]=true;
    for(int i=fi[x];i;i=ne[i])
    {
        int v=to[i];
        if(v==pr||pd[v]) continue;
        asd[v]=asd[x]^w[i];
        dfs2(v,x);
        val[x]+=val[v];
    }
}
void dfs3(int x,int pr)
{
    pd[x]=true;s[x]=s[pr]+val[x];
    for(int i=fi[x];i;i=ne[i])
    {
        int v=to[i];
        if(v==pr) continue;
        if(pd[v])
        {
            if(dep[v]>dep[x]) continue;
            if((dep[x]-dep[v])==(s[x]-s[v]))
                ans^=asd[x]^asd[v]^w[i];
            continue;
        }
        dfs3(v,x);
    }
}
int main()
{
    int size=40<<20;//40M
    __asm__ ("movq %0,%%rsp\n"::"r"((char*)malloc(size)+size));
    n=read(),m=read();
    for(int i=1;i<=m;++i)
    {
        int a=read(),b=read();
        add(a,b,i);add(b,a,i);
    }
    dfs1(1,0);
    for(int i=1;i<=n;++i)pd[i]=false;
    dfs2(1,0);
    for(int i=1;i<=n;++i)pd[i]=false;
    dfs3(1,0);
    cout<<ans;
    exit(0);
}

猜你喜欢

转载自www.cnblogs.com/zmyzmy/p/12112294.html