Luogu P2194 HXY烧情侣

省选前颓几道水题?

言归正传:
显然这是一道TARJAN,题面已经想方设法在提醒你了

这里还有一道双倍经验,稍微改一丢丢就可以了

只要记录每个强联通分量中的最小元素值和最小元素值对应的数量即可

看到很多题解都是全部处理完之后在最后统计最小元素值和最小元素对应数量并统计两个答案的,其实对于减小常数来说这样是没必要的,因为每个强连通分量只会在tarjan的途中被搜索到一次(可以叫做无后效性?)所以只要一边tarjan一边统计答案即可

#include<cstdio>
#include<iostream>
#include<cstdlib>
#include<cstring>
#define writep(x) write(x),putchar(' ')
#define writeln(x) write(x),puts("") 
#define ha 1000000007//珍惜生命,暴力取膜不可取,所以,我们取ha
using namespace std;
inline int read(){
    int ans=0,f=1;char chr=getchar();
    while(!isdigit(chr)){if(chr=='-') f=-1;chr=getchar();}
    while(isdigit(chr)){ans=(ans<<3)+(ans<<1)+chr-48;chr=getchar();}
    return ans*f;
}void write(int x){
    if(x<0) putchar('-'),x=-x;
    if(x>9) write(x/10);
    putchar(x%10+'0');
}const int M=3e5+5;
int n,m,a[M],head[M],ver[M],nxt[M],tot,dfn[M],low[M],ins[M],sta[M],top,t,mn[M],col,color[M],cnt[M],mc[M],ans1,ans2=1;
/*
col 强连通分量数量
color[]强连通分量的编号
cnt[]强连通分量重元素个数(这里貌似没用)
mn[]强连通分量中值最小值
mc[]强连通分量中最小值个数
*/
inline void add(int x,int y){ver[++tot]=y;nxt[tot]=head[x];head[x]=tot;}
inline void cmin(int &a,int b){if(a>b) a=b;}
void Tarjan(int x){
    dfn[x]=low[x]=++t;ins[x]=1,sta[top++]=x;
    for(register int i=head[x];i;i=nxt[i])
        if(ins[ver[i]]==0) Tarjan(ver[i]),cmin(low[x],low[ver[i]]);
        else if(ins[ver[i]]==1) cmin(low[x],dfn[ver[i]]);
    if(dfn[x]==low[x]) ++col,mn[col]=0x7fffffff;
    if(dfn[x]==low[x]){
        do{
            --top,++cnt[col],color[sta[top]]=col;ins[sta[top]]=-1;
            if(mn[col]>a[sta[top]])  mn[col]=a[sta[top]],mc[col]=0;
            if(mn[col]==a[sta[top]]) ++mc[col];//关键部分
        }while(sta[top]!=x);
        ans1+=mn[col];ans2=ans2*mc[col]%ha;//记录答案
    }
    
}
int main(){
    n=read();for(register int i=1;i<=n;++i) a[i]=read();
    m=read();for(register int i=1,x,y;i<=m;++i){x=read(),y=read(),add(x,y);}
    for(register int i=1;i<=n;++i) if(!dfn[i]) Tarjan(i);//基本操作
    writep(ans1),writeln(ans2);//输出
    return 0;
}

转载于:https://www.cnblogs.com/zhenglw/p/10752577.html

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值