bzoj2208[Jsoi2010]连通数
题意:
给一个有向图,每个点对答案的贡献为该点可达的点个数,求答案。n≤2000,m≤4000000。
题解:
听说暴力可过QAQ不过为了练tanjan还是写了常规写法。
先缩点,接着对每个入度为0的点做dp,每个点维护一个bitset。对于当前点,先将该点对应bitset的该点位置置为1,之后将这个bitset与该点所有子节点的bitset合并,然后枚举每个点,如果该点对应在bitset位置为1,则答案加上当前点的在原图中代表的点个数*该点在原图中代表的点个数。
代码:
1 #include <cstdio> 2 #include <cstring> 3 #include <algorithm> 4 #include <stack> 5 #include <bitset> 6 #define inc(i,j,k) for(int i=j;i<=k;i++) 7 #define maxn 2010 8 using namespace std; 9 10 inline int read(){ 11 char ch=getchar(); int f=1,x=0; 12 while(ch<'0'||ch>'9'){if(ch=='-')f=-1; ch=getchar();} 13 while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar(); 14 return f*x; 15 } 16 struct e{int t,n;}es[2][maxn*maxn]; int ess[2],g[2][maxn]; 17 void pe(int f,int t,bool o){ 18 es[o][++ess[o]]=(e){t,g[o][f]}; g[o][f]=ess[o]; 19 } 20 int dfn[maxn],low[maxn],tim,scc[maxn],sz[maxn],tot,ans,n; bool ins[maxn],not0[maxn]; stack<int>st; 21 void tarjan(int x){ 22 dfn[x]=low[x]=++tim; ins[x]=1; st.push(x); 23 for(int i=g[0][x];i;i=es[0][i].n){ 24 if(!dfn[es[0][i].t])tarjan(es[0][i].t),low[x]=min(low[x],low[es[0][i].t]); 25 else if(ins[es[0][i].t])low[x]=min(low[x],dfn[es[0][i].t]); 26 } 27 if(dfn[x]==low[x]){ 28 tot++; while(1){int y=st.top(); st.pop(); ins[y]=0; scc[y]=tot; sz[tot]++; if(x==y)break;} 29 } 30 } 31 bitset<maxn>bs[maxn]; bool vis[maxn]; 32 void dfs(int x){ 33 vis[x]=1; bs[x][x]=1; 34 for(int i=g[1][x];i;i=es[1][i].n){if(!vis[es[1][i].t])dfs(es[1][i].t); bs[x]|=bs[es[1][i].t];} 35 inc(i,1,tot)if(bs[x][i])ans+=sz[x]*sz[i]; 36 } 37 char s[maxn]; 38 int main(){ 39 n=read(); inc(i,1,n){scanf("%s",s+1); inc(j,1,n)if(s[j]-'0')pe(i,j,0);} inc(i,1,n)if(!dfn[i])tarjan(i); 40 inc(i,1,n) 41 for(int j=g[0][i];j;j=es[0][j].n) 42 if(scc[i]!=scc[es[0][j].t])pe(scc[i],scc[es[0][j].t],1),not0[scc[es[0][j].t]]=1; 43 inc(i,1,tot)if(!not0[i])dfs(i); printf("%d",ans); return 0; 44 }
20161115