图论笔记

圆方树

圆方树就是用 tarjan 跑出图中的所有点双,然后新建节点表示这个点双,分别与上面的割点和点双里的所有点连边,记得开二倍空间

P5058 [ZJOI2004] 嗅探器

这个题只有一次询问,所以就建完数判定一下两个点是否可达以及中间有没有原点即可

#include<bits/stdc++.h>
#define N 400005
using namespace std;
vector<int>y[N],w[N];
stack<int>Q;
int dfn[N],low[N],top=0,tot=0,fa[N],dep[N];
void tarjan(int u){
    Q.push(u);
    dfn[u]=low[u]=++top;
    for(int i=0;i<y[u].size();i++){
        if(dfn[y[u][i]]){
            low[u]=min(low[u],dfn[y[u][i]]);
            continue;
        }
        tarjan(y[u][i]);
        low[u]=min(low[u],low[y[u][i]]);
        if(low[y[u][i]]>=dfn[u]){
            tot++;
            w[tot].push_back(u);
            w[u].push_back(tot);
            while(Q.top()!=y[u][i]){
                w[Q.top()].push_back(tot);
                w[tot].push_back(Q.top());
                Q.pop();
            }
            w[Q.top()].push_back(tot);
            w[tot].push_back(Q.top());
            Q.pop();
        }
    }
    return;
}
void dfs(int u,int Fa){
    dep[u]=dep[Fa]+1;
    fa[u]=Fa;
    for(int i=0;i<w[u].size();i++)if(w[u][i]!=Fa)dfs(w[u][i],u);
    return;
}
signed main(){
    int n;
    scanf("%d",&n);
    tot=n;
    int u,v;
    scanf("%d%d",&u,&v);
    while(u&&v){
        y[u].push_back(v);
        y[v].push_back(u);
        scanf("%d%d",&u,&v);
    }
    scanf("%d%d",&u,&v);
    tarjan(u);
    while(!Q.empty()){
        w[u].push_back(Q.top());
        w[Q.top()].push_back(u);
        Q.pop();
    }
    dfs(u,0);
    if(!dfn[v]){
        printf("No solution\n");
        return 0;
    }
    int ans=n+1;
    v=fa[v];
    if(u==v){
        printf("No solution\n");
        return 0;
    }
    while(v!=u){
        if(v<=n)ans=min(ans,v);
        v=fa[v];
    }
    if(ans<=n)printf("%d\n",ans);
    else printf("No solution\n");
    return 0;
}

P4606 [SDOI2018] 战略游戏

这个麻烦点,需要搞出给定点的集合之间的所有路径,说白了就是建完虚树后所有的非选定点有多少是圆点

#include<bits/stdc++.h>
#define N 400005
using namespace std;
vector<int>y[N],w[N];
stack<int>Q;
int dfn[N],low[N],top=0,tot=0,dep[N],fa[N][22],dis[N][21],x[N],L[N],R[N],cnt=0,vis[N],f[N],used[N],n,m;
void tarjan(int u){
    dfn[u]=low[u]=++top;
    Q.push(u);
    for(int i=0;i<y[u].size();i++){
        if(dfn[y[u][i]]){
            low[u]=min(low[u],dfn[y[u][i]]);
            continue;
        }
        tarjan(y[u][i]);
        low[u]=min(low[u],low[y[u][i]]);
        if(low[y[u][i]]>=dfn[u]){
            tot++;
            w[tot].push_back(u);
            w[u].push_back(tot);
            while(Q.top()!=y[u][i]){
                w[Q.top()].push_back(tot);
                w[tot].push_back(Q.top());
                Q.pop();
            }
            w[Q.top()].push_back(tot);
            w[tot].push_back(Q.top());
            Q.pop();
        }
    }
    return;
}
void dfs(int u,int Fa){
    dep[u]=dep[Fa]+1;
    fa[u][0]=Fa;
    if(Fa&&Fa<=n)dis[u][0]=1;
    L[u]=++cnt;
    for(int i=0;i<w[u].size();i++)if(w[u][i]!=Fa)dfs(w[u][i],u);
    R[u]=cnt;
    return;
}
int DEP(int u,int v){
    int go=dep[u]-dep[v];
    for(int i=19;i>=0;i--)if(go&(1<<i))u=fa[u][i];
    return u;
}
int LCA(int u,int v){
    if(dep[u]<dep[v])swap(u,v);
    u=DEP(u,v);
    if(u==v)return u;
    for(int i=19;i>=0;i--)if(fa[u][i]!=fa[v][i]){
        u=fa[u][i];
        v=fa[v][i];
    }
    return fa[u][0];
}
bool cmp(int u,int v){return L[u]<L[v];}
signed main(){
    int T;
    scanf("%d",&T);
    while(T--){
        scanf("%d%d",&n,&m);
        tot=n;
        for(int i=1;i<=m;i++){
            int u,v;
            scanf("%d%d",&u,&v);
            y[u].push_back(v);
            y[v].push_back(u);
        }
        tarjan(1);
        dfs(1,0);
        dis[1][0]=0;
        for(int i=1;i<=19;i++)for(int j=1;j<=tot;j++){
            fa[j][i]=fa[fa[j][i-1]][i-1];
            dis[j][i]=dis[j][i-1]+dis[fa[j][i-1]][i-1];
        }
        int q;
        scanf("%d",&q);
        while(q--){
            int k;
            scanf("%d",&k);
            for(int i=1;i<=k;i++)scanf("%d",&x[i]);
            sort(x+1,x+k+1,cmp);
            for(int i=1;i<=k;i++)vis[i]=x[i];
            for(int i=1;i<k;i++)vis[k+i]=LCA(x[i],x[i+1]);
            sort(vis+1,vis+k*2,cmp);
            int num=unique(vis+1,vis+k*2)-vis-1;
            int now=1;
            for(int i=2;i<=num;i++){
                while(R[vis[now]]<L[vis[i]])now=f[now];
                f[i]=now;
                now=i;
            }
            int ans=0;
            for(int i=2;i<=num;i++){
                int go=dep[vis[i]]-dep[vis[f[i]]]-1;
                int u=vis[i];
                for(int j=19;j>=0;j--)if(go&(1<<j)){
                    ans+=dis[u][j];
                    u=fa[u][j];
                }
            }
            for(int i=1;i<=k;i++)used[x[i]]=1;
            for(int i=1;i<=num;i++)if(!used[vis[i]]&&vis[i]<=n)ans++;
            for(int i=1;i<=k;i++)used[x[i]]=0;
            printf("%d\n",ans);
        }
        for(int i=1;i<=tot;i++){
            for(int j=0;j<=19;j++)fa[i][j]=dis[i][j]=0;
            dfn[i]=low[i]=dep[i]=x[i]=L[i]=R[i]=vis[i]=f[i]=used[i]=0;
            w[i].clear();
            y[i].clear();
        }
        top=tot=cnt=0;
        while(!Q.empty())Q.pop();
    }
    return 0;
}
posted @ 2025-09-08 20:57  Igunareo  阅读(18)  评论(0)    收藏  举报