40/60/90/100 pts 求助

P3387 【模板】缩点

90pts ``` #include<bits/stdc++.h> using namespace std; struct graph1 { /* 图模板,tarjan 求强连通分量部分。 ==========函数表========== link(x,y,v) 结点 x 向结点 y 连接一条权值为 v 的有向边 x,y 结点编号 v 边权 tarjan_DFS(x,f) 以结点 x 为起始结点,进行 DFS,深度为 f x 结点编号 f 遍历深度 tarjan() 求强连通分量 ==========变量表========== total_point 总结点数 total_edge 总边数 total_scc 强连通分量数 first[i] 链式前向星 to[i] 链式前向星 next[i] 链式前向星 val[i] 第 i 条边的边权 dfn[i] 第 i 个结点的被遍历的顺序 low[i] 第 i 个结点及其能连向的所有结点中,dfn 的最小值 visit[i] 第 i 个结点已被遍历 scc[i] 第 i 个结点所在的强连通分量编号 S tarjan 需要用到的栈 */ static const int POINT_MAX=1e5+10,EDGE_MAX=2e5+10; int total_point=0,total_edge=0,first[POINT_MAX]={0},to[EDGE_MAX]={0},next[EDGE_MAX]={0}; int val[EDGE_MAX]={0}; int dfn[POINT_MAX]={0},low[POINT_MAX]={0},scc[POINT_MAX]; int total_scc=0; bool visit[POINT_MAX]={0}; stack<int>S; void link(int x,int y,int v=-1) { to[++total_edge]=y; next[total_edge]=first[x]; first[x]=total_edge; val[total_edge]=v; total_point=max(total_point,max(x,y)); } void tarjan_DFS(int x,int f) { dfn[x]=f; low[x]=f; S.push(x); visit[x]=1; for(int i=first[x];i;i=next[i]) { if(dfn[to[i]]==0) { tarjan_DFS(to[i],f+1); low[x]=min(low[x],low[to[i]]); } else if(visit[to[i]]) low[x]=min(low[x],low[to[i]]); } if(dfn[x]==low[x]) { total_scc++; scc[x]=total_scc; visit[x]=0; while(S.top()!=x) { scc[S.top()]=total_scc; visit[S.top()]=0; S.pop(); } S.pop(); } } void tarjan() { for(int i=1;i<=total_point;i++) if(!dfn[i]) tarjan_DFS(i,1); } }; struct graph2 { /* 图模板,拓扑排序部分。 ==========函数表========== link(x,y,v) 结点 x 向结点 y 连接一条权值为 v 的有向边 x,y 结点编号 v 边权 topology_sort() 拓扑排序框架 ==========变量表========== total_point 总结点数 total_edge 总边数 first[i] 链式前向星 to[i] 链式前向星 next[i] 链式前向星 val[i] 第 i 条边的边权 in_degree[i] 第 i 个结点的入度 Q 拓扑排序需要的队列 */ static const int POINT_MAX=1e5+10,EDGE_MAX=2e5+10; queue<int>Q; int total_point=0,total_edge=0,first[POINT_MAX]={0},to[EDGE_MAX]={0},next[EDGE_MAX]={0}; int val[EDGE_MAX]={0}; int pval[POINT_MAX]={0}; int in_degree[POINT_MAX]; int dp[POINT_MAX]; void link(int x,int y,int v=-1) { to[++total_edge]=y; next[total_edge]=first[x]; first[x]=total_edge; val[total_edge]=v; total_point=max(total_point,max(x,y)); } void topology_sort() { while(!Q.empty()) Q.pop(); for(int i=1;i<=total_point;i++) for(int j=first[i];j;j=next[j]) in_degree[to[j]]++; for(int i=1;i<=total_point;i++) if(in_degree[i]==0) Q.push(i); while(!Q.empty()) { int t=Q.front(); dp[t]=max(dp[t],pval[t]); Q.pop(); for(int i=first[t];i;i=next[i]) { dp[to[i]]=max(dp[to[i]],dp[t]+pval[to[i]]); in_degree[to[i]]--; if(in_degree[to[i]]==0) Q.push(to[i]); } } } }; graph1 G1; graph2 G2; int a[100010]; int main() { int n,m; scanf("%d%d",&n,&m); for(int i=1;i<=n;i++) scanf("%d",&a[i]); for(int i=1;i<=m;i++) { int x,y; scanf("%d%d",&x,&y); G1.link(x,y); } G1.tarjan(); for(int i=1;i<=n;i++) G2.pval[G1.scc[i]]+=a[i]; for(int i=1;i<=n;i++) for(int j=G1.first[i];j;j=G1.next[j]) if(G1.scc[i]!=G1.scc[G1.to[j]]) G2.link(G1.scc[i],G1.scc[G1.to[j]]); G2.topology_sort(); int ans=0; for(int i=1;i<=G1.total_scc;i++) ans=max(ans,G2.pval[i]); for(int i=1;i<=G1.total_scc;i++) ans=max(ans,G2.dp[i]); printf("%d",ans); return 0; } ```
by TianLuen @ 2022-10-26 23:42:23


40pts ``` #include<bits/stdc++.h> using namespace std; struct graph1 { /* 图模板,tarjan 求强连通分量部分。 ==========函数表========== link(x,y,v) 结点 x 向结点 y 连接一条权值为 v 的有向边 x,y 结点编号 v 边权 tarjan_DFS(x,f) 以结点 x 为起始结点,进行 DFS,深度为 f x 结点编号 f 遍历深度 tarjan() 求强连通分量 ==========变量表========== total_point 总结点数 total_edge 总边数 total_scc 强连通分量数 first[i] 链式前向星 to[i] 链式前向星 next[i] 链式前向星 val[i] 第 i 条边的边权 dfn[i] 第 i 个结点的被遍历的顺序 low[i] 第 i 个结点及其能连向的所有结点中,dfn 的最小值 visit[i] 第 i 个结点已被遍历 scc[i] 第 i 个结点所在的强连通分量编号 S tarjan 需要用到的栈 */ static const int POINT_MAX=1e5+10,EDGE_MAX=1e5+10; int total_point=0,total_edge=0,first[POINT_MAX]={0},to[EDGE_MAX]={0},next[EDGE_MAX]={0}; int val[EDGE_MAX]={0}; int dfn[POINT_MAX]={0},low[POINT_MAX]={0},scc[POINT_MAX]; int total_scc=0; bool visit[POINT_MAX]={0}; stack<int>S; void link(int x,int y,int v=-1) { to[++total_edge]=y; next[total_edge]=first[x]; first[x]=total_edge; val[total_edge]=v; total_point=max(total_point,max(x,y)); } void tarjan_DFS(int x,int f) { dfn[x]=f; low[x]=f; S.push(x); visit[x]=1; for(int i=first[x];i;i=next[i]) { if(dfn[to[i]]==0) { tarjan_DFS(to[i],f+1); low[x]=min(low[x],low[to[i]]); } else if(visit[to[i]]) low[x]=min(low[x],low[to[i]]); } if(dfn[x]==low[x]) { total_scc++; scc[x]=total_scc; visit[x]=0; while(S.top()!=x) { scc[S.top()]=total_scc; visit[S.top()]=0; S.pop(); } S.pop(); } } void tarjan() { for(int i=1;i<=total_point;i++) if(!dfn[i]) tarjan_DFS(i,1); } }; struct graph2 { /* 图模板,拓扑排序部分。 ==========函数表========== link(x,y,v) 结点 x 向结点 y 连接一条权值为 v 的有向边 x,y 结点编号 v 边权 topology_sort() 拓扑排序框架 ==========变量表========== total_point 总结点数 total_edge 总边数 first[i] 链式前向星 to[i] 链式前向星 next[i] 链式前向星 val[i] 第 i 条边的边权 in_degree[i] 第 i 个结点的入度 Q 拓扑排序需要的队列 */ static const int POINT_MAX=1e5+10,EDGE_MAX=1e5+10; queue<int>Q; int total_point=0,total_edge=0,first[POINT_MAX]={0},to[EDGE_MAX]={0},next[EDGE_MAX]={0}; int val[EDGE_MAX]={0}; int pval[POINT_MAX]={0}; int in_degree[POINT_MAX]; int dp[POINT_MAX]; void link(int x,int y,int v=-1) { to[++total_edge]=y; next[total_edge]=first[x]; first[x]=total_edge; val[total_edge]=v; total_point=max(total_point,max(x,y)); } void topology_sort() { while(!Q.empty()) Q.pop(); for(int i=1;i<=total_point;i++) for(int j=first[i];j;j=next[j]) in_degree[to[j]]++; for(int i=1;i<=total_point;i++) if(in_degree[i]==0) Q.push(i); while(!Q.empty()) { int t=Q.front(); dp[t]=max(dp[t],pval[t]); Q.pop(); for(int i=first[t];i;i=next[i]) { dp[to[i]]=max(dp[to[i]],dp[t]+pval[to[i]]); in_degree[to[i]]--; if(in_degree[to[i]]==0) Q.push(to[i]); } } } }; graph1 G1; graph2 G2; int a[100010]; bool _[10010][10010]; int main() { int n,m; scanf("%d%d",&n,&m); for(int i=1;i<=n;i++) scanf("%d",&a[i]); for(int i=1;i<=m;i++) { int x,y; scanf("%d%d",&x,&y); G1.link(x,y); } G1.tarjan(); for(int i=1;i<=n;i++) G2.pval[G1.scc[i]]+=a[i]; for(int i=1;i<=n;i++) for(int j=G1.first[i];j;j=G1.next[j]) if(G1.scc[i]!=G1.scc[G1.to[j]]) _[G1.scc[i]][G1.scc[G1.to[j]]]=1; for(int i=1;i<=G1.total_scc;i++) for(int j=i+1;j<=G1.total_scc;j++) if(_[i][j]) G2.link(j,i); G2.topology_sort(); int ans=0; for(int i=1;i<=G1.total_scc;i++) ans=max(ans,G2.pval[i]); for(int i=1;i<=G1.total_scc;i++) ans=max(ans,G2.dp[i]); printf("%d",ans); return 0; } ```
by TianLuen @ 2022-10-26 23:43:02


60pts ``` #include<bits/stdc++.h> using namespace std; struct graph1 { /* 图模板,tarjan 求强连通分量部分。 ==========函数表========== link(x,y,v) 结点 x 向结点 y 连接一条权值为 v 的有向边 x,y 结点编号 v 边权 tarjan_DFS(x,f) 以结点 x 为起始结点,进行 DFS,深度为 f x 结点编号 f 遍历深度 tarjan() 求强连通分量 ==========变量表========== total_point 总结点数 total_edge 总边数 total_scc 强连通分量数 first[i] 链式前向星 to[i] 链式前向星 next[i] 链式前向星 val[i] 第 i 条边的边权 dfn[i] 第 i 个结点的被遍历的顺序 low[i] 第 i 个结点及其能连向的所有结点中,dfn 的最小值 visit[i] 第 i 个结点已被遍历 scc[i] 第 i 个结点所在的强连通分量编号 S tarjan 需要用到的栈 */ static const int POINT_MAX=1e5+10,EDGE_MAX=2e5+10; int total_point=0,total_edge=0,first[POINT_MAX]={0},to[EDGE_MAX]={0},next[EDGE_MAX]={0}; int val[EDGE_MAX]={0}; int dfn[POINT_MAX]={0},low[POINT_MAX]={0},scc[POINT_MAX]; int total_scc=0; bool visit[POINT_MAX]={0}; stack<int>S; void link(int x,int y,int v=-1) { to[++total_edge]=y; next[total_edge]=first[x]; first[x]=total_edge; val[total_edge]=v; total_point=max(total_point,max(x,y)); } int tim=0; void tarjan_DFS(int x) { dfn[x]=++tim; low[x]=tim; S.push(x); visit[x]=1; for(int i=first[x];i;i=next[i]) { if(dfn[to[i]]==0) { tarjan_DFS(to[i]); low[x]=min(low[x],low[to[i]]); } else if(visit[to[i]]) low[x]=min(low[x],low[to[i]]); } if(dfn[x]==low[x]) { total_scc++; scc[x]=total_scc; visit[x]=0; while(S.top()!=x) { scc[S.top()]=total_scc; visit[S.top()]=0; S.pop(); } S.pop(); } } void tarjan() { for(int i=1;i<=total_point;i++) if(!dfn[i]) tarjan_DFS(i); } }; struct graph2 { /* 图模板,拓扑排序部分。 ==========函数表========== link(x,y,v) 结点 x 向结点 y 连接一条权值为 v 的有向边 x,y 结点编号 v 边权 topology_sort() 拓扑排序框架 ==========变量表========== total_point 总结点数 total_edge 总边数 first[i] 链式前向星 to[i] 链式前向星 next[i] 链式前向星 val[i] 第 i 条边的边权 in_degree[i] 第 i 个结点的入度 Q 拓扑排序需要的队列 */ static const int POINT_MAX=1e5+10,EDGE_MAX=2e5+10; queue<int>Q; int total_point=0,total_edge=0,first[POINT_MAX]={0},to[EDGE_MAX]={0},next[EDGE_MAX]={0}; int val[EDGE_MAX]={0}; int pval[POINT_MAX]={0}; int in_degree[POINT_MAX]; int dp[POINT_MAX]; void link(int x,int y,int v=-1) { to[++total_edge]=y; next[total_edge]=first[x]; first[x]=total_edge; val[total_edge]=v; total_point=max(total_point,max(x,y)); } void topology_sort() { while(!Q.empty()) Q.pop(); for(int i=1;i<=total_point;i++) for(int j=first[i];j;j=next[j]) in_degree[to[j]]++; for(int i=1;i<=total_point;i++) if(in_degree[i]==0) Q.push(i); for(int i=1;i<=total_point;i++) dp[i]=pval[i]; while(!Q.empty()) { int t=Q.front(); Q.pop(); for(int i=first[t];i;i=next[i]) { dp[to[i]]=max(dp[to[i]],dp[t]+pval[to[i]]); in_degree[to[i]]--; if(in_degree[to[i]]==0) Q.push(to[i]); } } } }; graph1 G1; graph2 G2; int a[100010]; int main() { int n,m; scanf("%d%d",&n,&m); for(int i=1;i<=n;i++) scanf("%d",&a[i]); for(int i=1;i<=m;i++) { int x,y; scanf("%d%d",&x,&y); G1.link(x,y); } G1.tarjan(); for(int i=1;i<=n;i++) for(int j=G1.first[i];j;j=G1.next[j]) if(G1.scc[i]!=G1.scc[G1.to[j]]) G2.link(G1.scc[i],G1.scc[G1.to[j]]); for(int i=1;i<=n;i++) G2.pval[G1.scc[i]]+=a[i]; G2.topology_sort(); int ans=0; for(int i=0;i<=G2.total_point;i++) ans=max(ans,G2.pval[i]); for(int i=0;i<=G2.total_point;i++) ans=max(ans,G2.dp[i]); printf("%d",ans); return 0; } ```
by TianLuen @ 2022-10-26 23:43:31


@[TianLuen](/user/239988) `dfs` 序不是深度,每个节点的 `dfs` 序需要不同。
by Usada_Pekora @ 2022-10-27 07:18:05


只需把 tarjan 改成 `dfn[x] = low[x] = ++idx;`。
by Usada_Pekora @ 2022-10-27 07:18:42


@[TianLuen](/user/239988) 你想知道的应该是你的那份代码是怎么过的。
by XHY20180718 @ 2022-11-06 16:40:21


@[TianLuen](/user/239988) dfn是时间戳,指的是遍历到该店的时间点,而不是深度额。。。 你的AC代码应该是凑巧过的(个人猜测)。
by XHY20180718 @ 2022-11-06 16:41:58


|