1. 程式人生 > >[BZOJ4484] [JSOI2015] 最小表示[拓撲排序+bitset]

[BZOJ4484] [JSOI2015] 最小表示[拓撲排序+bitset]

clu 利用 struct void push 圖的連通性 str bitset typename

題意

給你一個 \(n\) 個點 \(m\) 條邊的 \(\rm DAG\) ,詢問最多能夠刪除多少條邊,使得圖的連通性不變

  • \(n\leq 3\times 10^4\ ,m\leq 10^5\)

分析

  • 假設有點 \(u,v,x\) ,且有邊 \(u \rightarrow v,\ u \rightarrow x,\ x \rightarrow v\),那麽此時 \(u \rightarrow v\) 這條邊可以被刪除。

  • 於是直接拓撲排序,利用 \(bitset\) 求出每個點可以到達的點集合可以被到達的點集。

  • 對於每個點再搞一個 \(bitset\) 表示這個點連了邊的集合。

  • 如果一個點 \(v\)

    可以被刪除,那麽顯然\(u\) 可以從它連向的其他點走到 \(v\)
    因為無環所以不存在雙向依賴的關系,也就是說一條邊能不能刪並不被其他邊是否能刪所影響。

  • 總時間復雜度為 \(O(m*\frac{n}{32})\)

代碼

#include<bits/stdc++.h>
using namespace std;
#define go(u) for(int i=head[u],v=e[i].to;i;i=e[i].last,v=e[i].to)
#define rep(i,a,b) for(int i=a;i<=b;++i)
#define pb push_back
#define re(x) memset(x,0,sizeof x)
typedef long long LL;
inline int gi(){
    int x=0,f=1;char ch=getchar();
    while(!isdigit(ch)) {if(ch=='-') f=-1;ch=getchar();}
    while(isdigit(ch)){x=(x<<3)+(x<<1)+ch-48;ch=getchar();}
    return x*f;
}
template<typename T>inline bool Max(T &a,T b){return a<b?a=b,1:0;}
template<typename T>inline bool Min(T &a,T b){return b<a?a=b,1:0;}
const int N=1e5 + 7;
int n,m,edc=1,ans;
int head[N],ind[N];
bitset<30004>to[30004],bto[30004],tmp;
struct edge{
    int last,to;
    edge(){}edge(int last,int to):last(last),to(to){}
}e[N*2];
void Add(int a,int b){
    e[++edc]=edge(head[a],b),head[a]=edc;
    e[++edc]=edge(head[b],a),head[b]=edc;
}
int q[N],hd=1,tl;
void topo(){
    rep(i,1,n) if(!ind[i]) q[++tl]=i;
    for(;hd<=tl;++hd){
        int u=q[hd];
        go(u)if(!(i&1))
            if(--ind[v]==0) q[++tl]=v;
    }
    for(int j=tl;j;--j){
        int u=q[j];to[u][u]=1;
        go(u)if(i&1) to[v]|=to[u];
    }
    for(int j=1;j<=tl;++j){
        int u=q[j];bto[u][u]=1;
        go(u)if(!(i&1)) bto[v]|=bto[u];
    }
}
int main(){
    n=gi(),m=gi();
    rep(i,1,m){
        int a=gi(),b=gi();
        Add(a,b);++ind[b];
    }
    topo();
    for(int u=1;u<=n;++u){
        tmp.reset();
        go(u)if(!(i&1)) tmp[v]=1;
        go(u)if(!(i&1)&&(tmp&bto[v]).count()>1) ++ans;
    }
    printf("%d\n",ans);
    return 0;
}

[BZOJ4484] [JSOI2015] 最小表示[拓撲排序+bitset]