Tarjan-bzoj1093: [ZJOI2007]最大半连通子图

http://www.lydsy.com/JudgeOnline/problem.php?id=1093
先太监缩点,之后就变成了拓扑图;
第一问就是问最长链嘛,这个大家基本上全在用拓扑排序去搞;
其实dfs就好了……………………..
然后,求数量,这个直接在dfs里面乱搞就好了;
然后这个取模,如果你dp的话没问题;
反正dfs的时候要比较大小的;
这个时候就用高精度就好了;
就是再开一个数组存x取了几次莫;
然后比较就乱搞;
但是会重边;
其实我们只要dfs到一个点x时;
我们去搜索其子节点的时候不去重复;
那么直接再搞一个数组就好了;

#include<cstdio>
#include<cstdlib>
#include<iostream>
#include<algorithm>
#include<cmath>
#include<cstring>
#define Ll long long
using namespace std;
struct cs{
    Ll to,next;
}a[1000001];//f[i]是i点的最优结果;ff[i]是结果的次数%X;fff[i]是结果取了几次%; 
Ll head[100001],tt[100001],lin[100001],low[100001],c[1000001][2],q[100001],f[100001],ff[100001],fff[100001],sum[100001];
bool in[100001];
Ll x,y,z,n,m,ans,ll,Ans,ANS,t,X,nn;
void init(Ll x,Ll y){
    a[++ll].to=y;
    a[ll].next=head[x];
    head[x]=ll;
}
void dfs(Ll x){
    low[x]=tt[x]=++t; in[x]=1; q[++q[0]]=x;
    for(int k=head[x];k;k=a[k].next){
        if(!tt[a[k].to])dfs(a[k].to);
        if(in[a[k].to])low[x]=min(low[x],low[a[k].to]);
    }
    if(low[x]==tt[x]){
        nn++;
        while(1){
            lin[q[q[0]]]=nn;
            in[q[q[0]]]=0;
            sum[nn]++;
            q[0]--;
            if(q[q[0]+1]==x)break;
        }
    }
}
void find(Ll x){
    in[x]=1; t++;//这个tt代表循环次数 
    for(int k=head[x];k;k=a[k].next){
        if(!in[a[k].to])find(a[k].to);
        //其实我的程序有鬼的,但是不知为什么AC了
        //我的t在同一层会变的啊!!!!!; 
        if(tt[a[k].to]==t)continue;else tt[a[k].to]=t;//这个就是去重边,t++就免去了memset; 
        if(f[a[k].to]==f[x]){
             ff[x]+= ff[a[k].to];
            fff[x]+=fff[a[k].to];//类似高精度 
            fff[x]+=ff[x]/X;
            ff[x]%=X;       
        }
        if(f[a[k].to]>f[x])f[x]=f[a[k].to],ff[x]=ff[a[k].to],fff[x]=fff[a[k].to];
    }
    if(f[x])f[x]+=sum[x];else f[x]=sum[x],ff[x]=1,fff[x]=0;
    if(f[x]==ans){
        Ans+=ff[x];
        ANS+=fff[x];
        ANS+=Ans/X;
        Ans%=X;
    }
    if(f[x]>ans)ans=f[x],Ans=ff[x],ANS=fff[x];
}
int main()
{
    scanf("%lld%lld%lld",&n,&m,&X);
    for(int i=1;i<=m;i++){
        scanf("%lld%lld",&c[i][0],&c[i][1]);
        init(c[i][0],c[i][1]);
    }
    for(int i=1;i<=n;i++)if(!tt[i])dfs(i);//tarjan 
    memset(head,0,sizeof head);ll=0;
    for(int i=1;i<=m;i++){
        x=lin[c[i][0]];y=lin[c[i][1]];
        if(x==y)continue;
        init(x,y);
    }
    memset(in,0,sizeof in);
    memset(tt,0,sizeof tt);t=0;
    for(int i=1;i<=nn;i++)if(!in[i])find(i);
    printf("%lld\n%lld",ans,Ans);
}

其实这个程序问题很大;
首先根本不用fff数组呵呵呵;
呵呵呵呵呵呵………………..
ANS答案根本无关系
然后那个t还有漏洞(数据水)
其实那个t要另开变量存起来……..
但是思路是对的
那就不改了.
呵呵呵呵呵呵呵呵呵呵呵呵呵呵呵呵呵呵
感谢jzqjzq指出我的错误;本垃圾;还需大家指点;

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值