[BZOJ1093][ZJOI2007]最大半连通子图

来源:互联网 发布:卸载软件下载 编辑:程序博客网 时间:2024/04/29 03:57

先缩点,就转化成了求一条最长链和求有多少条这样的最长链。
关键是第二个的dp,设dp[i]表示到第i个点,有多少条最长路经过它,那么
dp[i]+=dp[u]
(ui,dis[u]+w[v]=dis[v])

#include<ctime>#include<cstdio>#include<cstdlib>#include<cstring>#include<algorithm>#include<iostream>#include<string>#include<cassert>#include<cmath>#include<vector>#include<queue>#include<stack>#include<map>#include<climits>#define X first#define Y second#define DB double#define MP make_pair#define LL long long#define pb push_back#define sqr(_) ((_)*(_))#define INF 0x3f3f3f3f#define pii pair<int,int>#define pdd pair<DB,DB>#define ull unsigned LL#define DEBUG(...) fprintf(stderr,__VA_ARGS__)using namespace std;const int MAXN=100000+10,MAXM=1000000+10;struct Graph{    int first[MAXN],next[MAXM],to[MAXM],size[MAXN],deg[MAXN];    int sccno[MAXN],e,scc_cnt,pre[MAXN],low[MAXN],dfs_clock;    stack<int> st;    Graph(){        memset(first,-1,sizeof(first));        memset(size,0,sizeof(size));        memset(pre,0,sizeof(pre));        memset(low,0,sizeof(pre));        memset(deg,0,sizeof(deg));        e=scc_cnt=dfs_clock=0;    }    void add(int a,int b)    {        next[e]=first[a];first[a]=e;to[e]=b;++e;deg[b]++;    }    void tarjan(int u)    {        pre[u]=low[u]=++dfs_clock;        st.push(u);        for(int i=first[u];i!=-1;i=next[i])        {            int v=to[i];            if(!pre[v])            {                tarjan(v);                low[u]=min(low[u],low[v]);            }            else if(!sccno[v])                low[u]=min(low[u],pre[v]);        }        if(low[u]==pre[u])        {            ++scc_cnt;            while(!st.empty())            {                int x=st.top();st.pop();                sccno[x]=scc_cnt;                size[scc_cnt]++;                if(x==u)                    break;            }        }    }}G[2];int n,m;int x,dp[2][MAXN],vis[MAXN];vector<int> c;void build(){    Graph* it=&G[0];    for(int i=1;i<=n;i++)//Warning    {        for(int j=it->first[i];j!=-1;j=it->next[j])        {            int v=it->to[j];            if(it->sccno[i]!=it->sccno[v])                G[1].add(it->sccno[i],it->sccno[v]);        }        //DEBUG("%d\n",c.size());    }    G[1].scc_cnt=G[0].scc_cnt;    memcpy(G[1].size,G[0].size,sizeof(G[0].size));}void work1(){    queue<int> q;    Graph* it=&G[1];    for(int i=1;i<=it->scc_cnt;i++)    {        if(!it->deg[i])        {            q.push(i);            dp[0][i]=it->size[i];            dp[1][i]++;        }    }    while(!q.empty())    {        int u=q.front();q.pop();        for(int i=it->first[u];i!=-1;i=it->next[i])        {            int v=it->to[i];            it->deg[v]--;            if(!it->deg[v])                q.push(v);            if(vis[v]==u)continue;            vis[v]=u;            if(dp[0][u]+it->size[v]>dp[0][v])            {                dp[0][v]=dp[0][u]+it->size[v];                dp[1][v]=dp[1][u];            }            else if(dp[0][u]+it->size[v]==dp[0][v])            {                dp[1][v]+=dp[1][u];                dp[1][v]%=x;            }        }    }    int ans1=0,ans2=0;    for(int i=1;i<=it->scc_cnt;i++)        ans1=max(ans1,dp[0][i]);    for(int i=1;i<=it->scc_cnt;i++)        if(dp[0][i]==ans1)        {            ans2+=dp[1][i];            ans2%=x;        }    cout<<ans1<<endl<<ans2<<endl;}int main(){#ifndef ONLINE_JUDGE    freopen("g.in","r",stdin);    freopen("g.out","w",stdout);#endif    scanf("%d %d %d",&n,&m,&x);    for(int i=1;i<=m;i++)    {        int a,b;        scanf("%d %d",&a,&b);        G[0].add(a,b);    }    for(int i=1;i<=n;i++)        if(!G[0].pre[i])            G[0].tarjan(i);    build();    work1();}
0 0
原创粉丝点击