传送门
题意:
给出一个有向图,求出分别删掉每条边之后强连通分量数量是否变化。
解析:
我用三个小时的浪费证明了一件事:
stack的空间常数比vector不知道大了多少倍。。。
最后把stack换成vector就AC了???
卡常三小时,AC一秒钟。。。
去UOJ群里面问了一下,标准规定的stack底层容器是deque???
然后手动改成stack<int,vector<int> > 发现空间小的不是一点半点。。。
思路:
首先删掉连接强连通分量的边是不可能增加联通快数量的。
那么考虑对每个连通分量内单独处理。
显然我们需要找的边一定是某个点到其他点路上的必经边。
考虑化边为点建立支配树。
随便选择一个原图中的点当做根就能建立支配树了,显然我们只需要考虑两种情况:它到其他点的必经边,其他点到它的必经边。
其中第二种情况显然只需要在反图上面处理就行了,仍然处理它到其他点的必经边。
需要建立 n n n棵支配树?
不,每个连通分量建立一棵就行了,根节点可以任意选择一个原图中的节点。
这么做的理由也很简单,如果一条边的删除会导致连通分量的增加,那么支配树必然会被它分成两部分,而我们随意选择的根必然在其中一个部分,所以怎么选择根都会把需要删除的边计算进来。
当然代码就十分的不忍直视了。。。
代码:
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define re register
#define gc get_char
#define pc put_char
#define cs const
namespace IO{
namespace IOONLY{
cs int Rlen=1<<20|1;
char buf[Rlen],*p1,*p2;
char obuf[Rlen],*p3=obuf;
char ch[23];
}
inline char get_char(){
using namespace IOONLY;
return (p1==p2)&&(p2=(p1=buf)+fread(buf,1,Rlen,stdin),p1==p2)?EOF:*p1++;
}
inline void put_char(char c){
using namespace IOONLY;
*p3++=c;
if(p3==obuf+Rlen)fwrite(obuf,1,Rlen,stdout),p3=obuf;
}
inline void FLUSH(){
using namespace IOONLY;
fwrite(obuf,1,p3-obuf,stdout),p3=obuf;
}
inline int getint(){
re int num;
re char c;
while(!isdigit(c=gc()));num=c^48;
while(isdigit(c=gc()))num=(num+(num<<2)<<1)+(c^48);
return num;
}
}
using namespace IO;
cs int N=300005;
namespace DT{
int n,st;
struct Graph{
vector<int> edge[N];
inline void clear(){for(int re i=1;i<=n;++i)edge[i].clear();}
inline void addedge(int u,int v){edge[u].push_back(v);}
}g,revg;
vector<int> dom[N];
int dfn[N],fa[N],id[N],dfs_clock;
void dfs(int u){
id[dfn[u]=++dfs_clock]=u;
for(int re e=0,v;e<g.edge[u].size();++e){
v=g.edge[u][e];
if(dfn[v])continue;
fa[v]=u;dfs(v);
}
}
int bel[N],val[N],semi[N],idom[N];
inline int getfa(int x){
if(bel[x]==x)return x;
int tmp=getfa(bel[x]);
if(dfn[semi[val[bel[x]]]]<dfn[semi[val[x]]])val[x]=val[bel[x]];
return bel[x]=tmp;
}
int du[N];
inline void tarjan(){
for(int re i=dfs_clock,u;i>1;--i){
u=id[i];
for(int re e=0,v;e<revg.edge[u].size();++e){
v=revg.edge[u][e];
if(!dfn[v])continue;
getfa(v);
if(dfn[semi[val[v]]]<dfn[semi[u]])semi[u]=semi[val[v]];
}
dom[semi[u]].push_back(u);
u=bel[u]=fa[u];
for(int re i=0;i<dom[u].size();++i){
int v=dom[u][i];
getfa(v);
if(semi[val[v]]==u)idom[v]=u;
else idom[v]=val[v];
}
dom[u].clear();
}
for(int re i=2;i<=dfs_clock;++i){
int u=id[i];
if(semi[u]^idom[u])idom[u]=idom[idom[u]];
++du[idom[u]];
}
}
inline void init(){
g.clear(),revg.clear();
for(int re i=1;i<=n;++i)semi[i]=bel[i]=val[i]=i,dfn[i]=0,du[i]=0;
dfs_clock=0;
}
inline void init(cs int &_n,cs vector<pair<int,int> > &edge,cs int &_st){
n=_n;st=_st;
init();
for(int re i=0;i<edge.size();++i){
int u=edge[i].first,v=edge[i].second;
g.addedge(u,v);
revg.addedge(v,u);
}
}
inline void build(){
dfs(st);
tarjan();
}
inline bool isleaf(int u){return !du[u];}
}
int n,m;
vector<int> edge[N];
inline void addedge(int u,int v){edge[u].push_back(v);}
int dfn[N],low[N],dfs_clock;
int scc[N],scc_clock;
bool ok[N];
vector<int> sta;
bool inst[N];
int pos[N],id[N],cnt;
void tarjan(int u){
dfn[u]=low[u]=++dfs_clock;
sta.push_back(u);
inst[u]=true;
for(int re e=0,v;e<edge[u].size();++e){
v=edge[u][e];
if(!dfn[v]){
tarjan(v);
low[u]=min(low[u],low[v]);
}
else if(inst[v])low[u]=min(low[u],dfn[v]);
}
if(low[u]==dfn[u]){
++scc_clock;
cnt=0;int st=0;
while(true){
int x=sta.back();sta.pop_back();
scc[x]=scc_clock;
pos[id[x]=++cnt]=x;
inst[x]=false;
if(x<=n&&!st)st=id[x];
if(x==u)break;
}
if(cnt==1)return ;
vector<pair<int,int> >edges;
for(int re i=1,u;i<=cnt;++i){
u=pos[i];
for(int re e=0,v;e<edge[u].size();++e){
v=edge[u][e];
if(scc[v]^scc_clock)continue;
edges.push_back(make_pair(id[v],id[u]));
}
}
DT::init(cnt,edges,st);
DT::build();
for(int re i=1;i<=cnt;++i){
if(DT::isleaf(i))continue;
int u=pos[i];
if(u>n)ok[u-n]=true;
}
edges.clear();
for(int re i=1,u;i<=cnt;++i){
u=pos[i];
for(int re e=0,v;e<edge[u].size();++e){
v=edge[u][e];
if(scc[v]^scc_clock)continue;
edges.push_back(make_pair(id[u],id[v]));
}
}
DT::init(cnt,edges,st);
DT::build();
for(int re i=1;i<=cnt;++i){
if(DT::isleaf(i))continue;
int u=pos[i];
if(u>n)ok[u-n]=true;
}
}
}
inline void init(){
for(int re i=1;i<=n+m;++i){
edge[i].clear();
dfn[i]=scc[i]=ok[i]=0;
}
dfs_clock=scc_clock=0;
}
inline void solve(){
n=getint(),m=getint();
for(int re i=1;i<=m;++i){
int u=getint(),v=getint();
addedge(u,i+n);
addedge(i+n,v);
}
for(int re i=1;i<=n+m;++i){
if(!dfn[i])tarjan(i);
}
for(int re i=1;i<=m;++i){
pc(ok[i]?'1':'0');
}
pc('\n');
}
signed main(){
for(int T=getint();T--;)init(),solve();
FLUSH();
return 0;
}