[BZOJ4484] [JSOI2015] 最小表示[拓撲排序+bitset]
阿新 • • 發佈:2018-10-16
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\)
因為無環所以不存在雙向依賴的關系,也就是說一條邊能不能刪並不被其他邊是否能刪所影響。總時間復雜度為 \(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]