【Codeforces 639F】Bear and Chemistry

边双缩点,虚树。

题目大意:

给定一张无向图,每次询问给出 $n’$ 个点和 $m’$ 条额外边,要求回答在加入 $m’$ 条额外边后,这 $n’$ 个点两两之间是否存在两条不包含重复边的路径。询问独立,强制在线。

题解:

相当于每次询问加入若干条边后,这个点集是否在同一个边双里。

首先对原图进行缩点,得到一棵树。

然后每次把给定的点集以及额外边的端点建出来,并连上边。

在这张图上再跑边双,判断给定的点是否在同一个边双里即可。

时间复杂度 $O((n+m)\log n)$。

由于需要进行很多次求边双,可以把求边双的东西封装起来减少代码长度。

Code:

#include<iostream>
#include<algorithm>
#include<vector>
#include<cstring>
using namespace std;
const int N=3e5+6;
struct edge{
    int to,nxt;
}e[N<<2];
int n,m,head[N],dfn[N],cnt,bel[N],nodes,dep[N],fa[N],top[N],son[N],sz[N],idx,idfn[N],out[N],k,rt[N],rr;
vector<int>sta;
int U[N],V[N],a[N];
bool vis[N];
inline void addedge(int u,int v){
    e[++cnt]=(edge){v,head[u]},head[u]=cnt;
}
struct Graph{
    edge e[N<<2];
    int head[N],cnt,id[N],n,dfn[N],low[N],idx,sta[N],top,bel[N],vis[N],SCC;
    inline void addedge(int u,int v){
        e[++cnt]=(edge){v,head[u]},head[u]=cnt;
        e[++cnt]=(edge){u,head[v]},head[v]=cnt;
    }
    void clear(){
        for(int i=1;i<=n;++i)head[id[i]]=dfn[id[i]]=low[id[i]]=bel[id[i]]=0;
        n=idx=0,cnt=1;
    }
    void dfs(int now,int ie){
        dfn[now]=low[now]=++idx;
        vis[now]=1;
        sta[++top]=now;
        for(int i=head[now];i;i=e[i].nxt)
        if(i!=ie){
            const int v=e[i].to;
            if(!dfn[v]){
                dfs(v,i^1);
                low[now]=min(low[now],low[v]);
            }else if(vis[v])low[now]=min(low[now],dfn[v]);
        }
        if(dfn[now]==low[now]){
            ++SCC;
            int v;
            do{
                v=sta[top--];
                vis[v]=0;
                bel[v]=SCC;
            }while(v!=now);
        }
    }
    void init(){
        for(int i=1;i<=n;++i)
        if(!dfn[id[i]])dfs(id[i],0);
    }
    void ready(const vector<int>&sta){
        n=sta.size();
        for(int i=1;i<=n;++i)id[i]=sta[i-1];
    }
    void save_out(){
        for(int i=1;i<=n;++i)
        ::head[id[i]]=0,::bel[id[i]]=bel[id[i]];
        for(int i=1;i<=n;++i)
        for(int j=head[id[i]];j;j=e[j].nxt)
        if(bel[id[i]]!=bel[e[j].to])::addedge(bel[id[i]],bel[e[j].to]);
        ::nodes=SCC;
    }
    bool judge(int*a,int siz){
        const int&t=bel[a[1]];
        for(int i=2;i<=siz;++i)
        if(bel[a[i]]!=t)return 0;
        return 1;
    }
}G,H;
inline bool cmp(const int&a,const int&b){
    return dfn[a]<dfn[b];
}
void dfs(int now){
    rt[now]=rr;
    sz[now]=1,son[now]=0,vis[now]=1;
    for(int i=head[now];i;i=e[i].nxt)
    if(!vis[e[i].to]){
        dep[e[i].to]=dep[now]+1,fa[e[i].to]=now;
        dfs(e[i].to);
        sz[now]+=sz[e[i].to];
        if(!son[now]||sz[son[now]]<sz[e[i].to])son[now]=e[i].to;
    }
}
void dfs2(int now){
    vis[now]=1;
    idfn[dfn[now]=++idx]=now;
    if(son[now])top[son[now]]=top[now],dfs2(son[now]);
    for(int i=head[now];i;i=e[i].nxt)
    if(!vis[e[i].to])dfs2(top[e[i].to]=e[i].to);
    out[now]=idx;
}
inline int LCA(int x,int y){
    while(top[x]!=top[y])
    if(dep[top[x]]>dep[top[y]])x=fa[top[x]];else y=fa[top[y]];
    return dep[x]<dep[y]?x:y;
}
void build(){
    static int stk[N];
    int top=1;stk[1]=sta[0];
    for(int i=1;i<sta.size();++i){
        const int&v=sta[i];
        while(top&&out[stk[top]]<dfn[v])--top;
        if(top)H.addedge(stk[top],v);
        stk[++top]=v;
    }
}
int main(){
    ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
    cin>>n>>m>>k;
    G.clear();
    for(int i=1;i<=n;++i)G.id[i]=i;
    G.n=n;
    for(int i=1;i<=m;++i){
        int u,v;
        cin>>u>>v;
        G.addedge(u,v);
    }
    G.init();
    G.save_out();
    memset(vis,0,sizeof vis);
    for(int i=1;i<=nodes;++i)if(!dep[i])dep[rr=i]=1,dfs(i);
    memset(vis,0,sizeof vis);
    for(int i=1;i<=nodes;++i)if(dep[i]==1)top[i]=1,dfs2(i);
    long long dat=0;
    for(int T=1;T<=k;++T){
        int nn,mm;
        cin>>nn>>mm;
        sta.clear();
        for(int i=1;i<=nn;++i){
            int x;
            cin>>x;
            x=(x+dat)%n;
            if(!x)x=n;
            sta.push_back(a[i]=bel[x]);
        }
        for(int i=1;i<=mm;++i){
            int x;
            cin>>x;
            x=(x+dat)%n;
            if(!x)x=n;
            sta.push_back(U[i]=bel[x]);
            cin>>x;
            x=(x+dat)%n;
            if(!x)x=n;
            sta.push_back(V[i]=bel[x]);
        }
        sort(sta.begin(),sta.end(),cmp);
        sta.erase(unique(sta.begin(),sta.end()),sta.end());
        for(int i=(int)sta.size()-1;i;--i)
        if(rt[sta[i]]==rt[sta[i-1]])
        sta.push_back(LCA(sta[i],sta[i-1]));
        sort(sta.begin(),sta.end(),cmp);
        sta.erase(unique(sta.begin(),sta.end()),sta.end());
        H.clear();
        H.ready(sta);
        build();
        for(int i=1;i<=mm;++i)H.addedge(U[i],V[i]);
        H.init();
        bool res=H.judge(a,nn);
        dat+=T*res;
        cout<<(res?"YES":"NO")<<'\n';
    }
    return 0;
}