一、模板
(1)tarjan模板
1 #define N 30100 2 //N为最大点数 3 #define M 150100 4 //M为最大边数 5 int n, m;//n m 为点数和边数 6 7 struct Edge{ 8 int from, to, nex; 9 bool sign;//是否为桥 10 }edge[M<<1]; 11 int head[N], edgenum; 12 void add(int u, int v){//边的起点和终点 13 Edge E={u, v, head[u], false}; 14 edge[edgenum] = E; 15 head[u] = edgenum++; 16 } 17 18 int DFN[N], Low[N], Stack[N], top, Time; //Low[u]是点集{u点及以u点为根的子树} 中(所有反向弧)能指向的(离根最近的祖先v) 的DFN[v]值(即v点时间戳) 19 int taj;//连通分支标号,从1开始 20 int Belong[N];//Belong[i] 表示i点属于的连通分支 21 bool Instack[N]; 22 vector<int> bcc[N]; //标号从1开始 23 24 void tarjan(int u ,int fa){ 25 DFN[u] = Low[u] = ++ Time ; 26 Stack[top ++ ] = u ; 27 Instack[u] = 1 ; 28 29 for (int i = head[u] ; ~i ; i = edge[i].nex ){ 30 int v = edge[i].to ; 31 if(DFN[v] == -1) 32 { 33 tarjan(v , u) ; 34 Low[u] = min(Low[u] ,Low[v]) ; 35 if(DFN[u] < Low[v]) 36 { 37 edge[i].sign = 1;//为割桥 38 } 39 } 40 else if(Instack[v]) Low[u] = min(Low[u] ,DFN[v]) ; 41 } 42 if(Low[u] == DFN[u]){ 43 int now; 44 taj ++ ; bcc[taj].clear(); 45 do{ 46 now = Stack[-- top] ; 47 Instack[now] = 0 ; 48 Belong [now] = taj ; 49 bcc[taj].push_back(now); 50 }while(now != u) ; 51 } 52 } 53 54 void tarjan_init(int all){ 55 memset(DFN, -1, sizeof(DFN)); 56 memset(Instack, 0, sizeof(Instack)); 57 top = Time = taj = 0; 58 for(int i=1;i<=all;i++)if(DFN[i]==-1 )tarjan(i, i); //注意开始点标!!! 59 } 60 vector<int>G[N]; 61 int du[N]; 62 void suodian(){ 63 memset(du, 0, sizeof(du)); 64 for(int i = 1; i <= taj; i++)G[i].clear(); 65 for(int i = 0; i < edgenum; i++){ 66 int u = Belong[edge[i].from], v = Belong[edge[i].to]; 67 if(u!=v)G[u].push_back(v), du[v]++; 68 } 69 } 70 void init(){memset(head, -1, sizeof(head)); edgenum=0;}
二、练习
1、【CodeForces 427C】 Checkposts
题意:n(1<=n<=10^5)个城市,m(1<=m<=10^5)条单向的路,现在要放一些保安来管理这n个城市,如果在第i个城市放保安,需要花费a[i](0<=a[i]<=10^9)的钱,如果城市j满足【保安能从i走到j,同时能从j走回到i】那么放在城市i的保安能管理城市j。求在哪些城市放保安能将这n个城市全都治理到,并且所花的钱最少,输出花的钱以及放保安的方案数。
解题思路:模板题,求出每个连通分量的最小花费minx[taj],以及最小花费的个数maxn[taj],花的最少钱是minx[]的和,方案数就是maxn[]的乘积。
1 #include <bits/stdc++.h> 2 using namespace std; 3 #define ll __int64 4 const int mod=1e9+7; 5 #define N 301000 6 //N为最大点数 7 #define M 150100 8 //M为最大边数 9 int n, m;//n m 为点数和边数 10 11 struct Edge{ 12 int from, to, nex; 13 }edge[N<<1]; 14 int head[N], edgenum; 15 void add(int u, int v){//边的起点和终点 16 Edge E={u, v, head[u]}; 17 edge[edgenum] = E; 18 head[u] = edgenum++; 19 } 20 21 int DFN[N], Low[N], Stack[N], top, Time; 22 //Low[u]是点集{u点及以u点为根的子树}中 23 //(所有反向弧)能指向的(离根最近的祖先v)的DFN[v]值(即v点时间戳) 24 int taj;//连通分支标号,从1开始 25 int Belong[N];//Belong[i] 表示i点属于的连通分支 26 bool Instack[N]; 27 ll pp[N], minx[N], maxn[N]; 28 void tarjan(int u ,int fa){ 29 DFN[u] = Low[u] = ++ Time ; 30 Stack[top ++ ] = u ; 31 Instack[u] = 1 ; 32 33 for (int i = head[u] ; ~i ; i = edge[i].nex ){ 34 int v = edge[i].to ; 35 if(DFN[v] == -1) 36 { 37 tarjan(v , u) ; 38 Low[u] = min(Low[u] ,Low[v]) ; 39 } 40 else if(Instack[v]) Low[u] = min(Low[u] ,DFN[v]) ; 41 } 42 if(Low[u] == DFN[u]){ 43 int now; 44 taj ++ ; 45 do{ 46 now = Stack[-- top] ; 47 Instack[now] = 0 ; 48 Belong [now] = taj ; 49 if(minx[taj]>pp[now]) minx[taj]=pp[now], maxn[taj]=0; 50 if(minx[taj]==pp[now]) maxn[taj]++; 51 }while(now != u) ; 52 } 53 } 54 55 void tarjan_init(int all){ 56 memset(DFN, -1, sizeof(DFN)); 57 memset(Instack, 0, sizeof(Instack)); 58 memset(minx, 0x3f3f3f3f, sizeof(minx)); 59 memset(maxn, 0, sizeof(maxn)); 60 top = Time = taj = 0; 61 for(int i=1;i<=all;i++)if(DFN[i]==-1 )tarjan(i, i); //注意开始点标!!! 62 } 63 void init(){memset(head, -1, sizeof(head)); edgenum=0;} 64 int main(){ 65 scanf("%d", &n); 66 init(); 67 for(int i=1; i<=n; i++) scanf("%d", &pp[i]); 68 scanf("%d", &m); 69 int u, v; 70 for(int i=0; i<m; i++){ 71 scanf("%d%d", &u, &v); 72 add(u, v); 73 } 74 tarjan_init(n); 75 ll ans=0, sum=1; 76 for(int i=1; i<=taj; i++){ 77 ans+=minx[i]; 78 sum = (sum*maxn[i])%mod; 79 } 80 printf("%I64d %I64d\n", ans, sum); 81 return 0; 82 }
时间: 2024-10-19 19:31:17