• 洛谷P2194HXY烧情侣


    传送门啦

    这个题可以说是tarjan强连通分量的裸题,但需要维护每个强连通分量的最小值,所以做法就很明确了。

    我们先明确几个数组的意思:

    1.首先是tarjan缩点中的几个数组:

      dfn[i]:i点的时间戳
    
      low[i],表示这个点以及其子孙节点连的所有点中dfn最小的值
    
      stack[],表示当前所有可能能构成是强连通分量的点。
    
      ins[i],表示 i 是否在stack[ ]数组中
      
      num[i],表示第 i 个强连通分量中有多少个点
      
      belong[i],表示第 i 点在哪一个强连通分量里
    

    2.然后是我们用来维护最小值以及最小 值个数的数组

      minn[i],表示第 i 个强连通分量中点权的最小值
      
      sum[]:表示最小值是 i 的有多少个
    

    最最最需要注意的两初始化:

    1.ans2 需要初始化为 1

    2.minn[i]这个数组要初始为正无穷。

    #include <iostream>
    #include <cstring>
    #include <cstdio>
    #include <algorithm>
    using namespace std;
    const long long mod = 1e9 + 7;
    const int maxn = 1e5 + 5;
    const int maxm = 3e5 + 4;
    
    int n,m,a[maxn],x,y;
    struct Edge{
    	int to,next,val;
    }edge[maxm << 1];
    int head[maxn],tot;
    int dfn[maxn],low[maxn],ind;
    int stack[maxn],top,cnt,num[maxn],belong[maxn];
    bool ins[maxn];
    int ans1,ans2 = 1,minn[maxn],sum[maxn];
    
    void add(int u,int v){
    	edge[++tot].to = v;
    	edge[tot].next = head[u];
    	head[u] = tot;
    }
    
    inline int read(){
    	char ch = getchar();
    	int f = 1 , x = 0;
    	while(ch > '9' || ch < '0'){
    		if(ch == '-') f = -1;
    		ch = getchar();
    	}
    	while(ch <= '9' && ch >= '0'){
    		x = x * 10 + ch - '0';
    		ch = getchar();
    	}
    	return x * f;
    }
    
    void print(int x){
    	if(x < 0){
    		putchar('-');
    		x = -x;
    	}
    	if(x > 9)  print(x / 10);
    	putchar(x % 10 + '0');
    }
    
    void tarjan(int x){
    	dfn[x] = low[x] = ++ind;
    	ins[x] = true;
    	stack[++top] = x;
    	for(int i=head[x];i;i=edge[i].next){
    		int v = edge[i].to;
    		if(ins[v])  low[x] = min(low[x] , dfn[v]);
    		if(!dfn[v]){
    			tarjan(v);
    			low[x] = min(low[x] , low[v]);
    		}
    	}
    	int k;
    	if(dfn[x] == low[x]){
    		++cnt;
    		do{
    			k = stack[top];
    			num[cnt]++;
    			ins[k] = false;
    			minn[cnt] = min(minn[cnt] , a[k]);
    			top--;
    			belong[k] = cnt;
    		}  while(k != x);
    	}
    }
    
    int main(){
    	n = read();
    	for(int i=1;i<=n;i++){
    		a[i] = read();
    	}
    	m = read();
    	for(int i=1;i<=m;i++){
    		x = read();  y = read();
    		add(x,y);
    	}
    	for(int i=1;i<=n;i++)
    	   minn[i] = 1e9;
    	for(int i=1;i<=n;i++)
    	  if(!dfn[i]) tarjan(i);
    	for(int i=1;i<=cnt;i++){
    		ans1 += minn[i];
    	}
    	print(ans1);
    	cout<<" ";
    	for(int i=1;i<=n;i++)
    	  if(a[i] == minn[belong[i]])
    	    sum[belong[i]]++;
    	for(int i=1;i<=cnt;i++)
    	  ans2 = ans2 * sum[i] % mod;
    	print(ans2);
    	return 0;
    }
    
    顺风不浪,逆风不怂。
  • 相关阅读:
    hdu 4396(spfs/二维最短路)
    hdu 4360(最短路变形)
    hdu 3501(欧拉函数的应用)
    bnu 4359(数位dp)
    用Hermite插值方法估计积分值
    虞旦盛老师 的《数学分析续》课件
    数值积分中的梯形法则
    数值积分中的梯形法则
    辛普森三八律
    利用自然数的标准分解证明可数集合的所有有限子集形成的集合是可数集
  • 原文地址:https://www.cnblogs.com/Stephen-F/p/9884651.html
Copyright © 2020-2023  润新知