BZOJ 4304 tarjan+topsort+bitset

我就是想骗一骗访问量

先Tarjan搞出来所有的强连通分量

正向连边 反向连边 topsort一发  搞出来每个点可以到哪些点 和哪些点可以到这个点

对于每条边 与一下  就是答案

 

//By SiriusRen
#include <bits/stdc++.h>
using namespace std;
const int N=2050,M=N*N;
int n,m,T,jy,ans,r=1;
int low[N],dfn[N],cnt,stk[N],vis[N],p[N],top;
set<int>s;
struct Edge{
    bitset<N>f[N];
    int mp[N][N],in[N];
    void topsort(){
        queue<int>q;
        for(int i=1;i<=T;i++)for(int j=1;j<=T;j++)if(mp[i][j])in[j]++;
        for(int i=1;i<=T;i++)if(!in[i])q.push(i);
        while(!q.empty()){
            int t=q.front();q.pop();
            for(int v=1;v<=T;v++)if(mp[t][v]){
                in[v]--,f[v]|=f[t];
                if(!in[v])q.push(v);
            }
        }
    }
}e[3];
struct Road{int x,y;Road(int X=0,int Y=0):x(X),y(Y){};}rd[M];
void tarjan(int x){
    low[x]=dfn[x]=++cnt,stk[++top]=x;vis[x]=1;
    for(int v=1;v<=n;v++)if(e[0].mp[x][v]){
        if(!dfn[v])tarjan(v),low[x]=min(low[x],low[v]);
        else if(vis[v])low[x]=min(low[x],dfn[v]);
    }if(low[x]==dfn[x]){T++;do{jy=stk[top--],vis[jy]=0;p[jy]=T;e[1].f[T][jy]=e[2].f[T][jy]=1;}while(jy!=x);}
}
int main(){
    scanf("%d%d",&n,&m);
    for(int i=1;i<=m;i++)scanf("%d%d",&rd[i].x,&rd[i].y),e[0].mp[rd[i].x][rd[i].y]=1;
    for(int i=1;i<=n;i++)if(!dfn[i])tarjan(i);
    for(int i=1;i<=m;i++)if(p[rd[i].x]!=p[rd[i].y])
        e[1].mp[p[rd[i].x]][p[rd[i].y]]=e[2].mp[p[rd[i].y]][p[rd[i].x]]=1;
    e[1].topsort();e[2].topsort();
    for(int i=1;i<=m;i++){
        int t=(int)(e[2].f[p[rd[i].x]]&e[1].f[p[rd[i].y]]).count();
        if(ans<t)s.clear(),ans=t,s.insert(i);
        else if(ans==t)s.insert(i);
    }
    printf("%d\n%d\n",ans,(int)s.size());
    for(set<int>::iterator it=s.begin();it!=s.end();it++,r++)printf("%d%c",*it,r==s.size()?'\n':' ');
}

 

posted @ 2017-06-13 20:15  SiriusRen  阅读(216)  评论(0编辑  收藏  举报