Luogu 1074(tarjan+dp)
来源:互联网 发布:matlab智能算法有哪些 编辑:程序博客网 时间:2024/05/21 08:35
传送门
NOIP 2009 T3
题解:可以用两边SPFA过,也可以用tarjan+dp过。
如果使用第二种方法,那么记录一下每个强连通分量内的最大最小值,然后设f[i]为从1所在强连通分量到i所在强连通分量,用类似SPFA的BFS更新f值,最后输出f[n]。
P.S.两边SPFA的做法:从1用正向边搜一遍最小值(最短路),从n用反向边搜一遍最大值(最长路),然后用两遍都经过的点的最大最小值之差更新答案即可。
Tarjan(SCC)+dp:
#include<cstdio>#include<cstring>#include<iostream>#include<algorithm>#include<stack>#include<queue>#include<vector>using namespace std;const int MAXN=1e5+4,MAXM=5e5+4;int n,m,a[MAXN];int low[MAXN],dfn[MAXN],bel[MAXN],tim=0,scc=0;int mn[MAXN],mx[MAXN],f[MAXN];bool ins[MAXN];int head[MAXN],etot=0;struct EDGE { int v,nxt;}e[MAXM<<1];stack<int > S;vector<int > G[MAXN];inline int read() { int x=0;char c=getchar(); while (c<'0'||c>'9') c=getchar(); while (c>='0'&&c<='9') x=x*10+c-'0',c=getchar(); return x;}inline void adde(int u,int v) { e[++etot].nxt=head[u],e[etot].v=v,head[u]=etot;}void dfs(int p) { low[p]=dfn[p]=++tim; S.push(p),ins[p]=true; for (int i=head[p];~i;i=e[i].nxt) { int v=e[i].v; if (!dfn[v]) { dfs(v); low[p]=min(low[p],low[v]); } else if (ins[v]) low[p]=min(low[p],dfn[v]); } if (low[p]==dfn[p]) { ++scc; while (1) { int t=S.top(); S.pop(); bel[t]=scc; mn[scc]=min(mn[scc],a[t]); mx[scc]=max(mx[scc],a[t]); ins[t]=false; if (t==p) break; } }}inline int bfs() { queue<int > q; int vis[MAXN]; memset(vis,false,sizeof(vis)); q.push(bel[1]),vis[bel[1]]=true; while (!q.empty()) { int p=q.front(); q.pop(); vis[p]=false; for (int i=0;i<G[p].size();++i) { int v=G[p][i]; mn[v]=min(mn[v],mn[p]); f[v]=max(f[v],f[p]); f[v]=max(f[v],mx[v]-mn[v]); if (!vis[v]) vis[v]=true,q.push(v); } } return f[bel[n]];}int main() {// freopen("P1073.in","r",stdin); memset(mn,0x3f,sizeof(mn)); memset(mx,0,sizeof(mx)); memset(head,-1,sizeof(head)); memset(dfn,0,sizeof(dfn)); memset(ins,false,sizeof(ins)); n=read(),m=read(); for (register int i=1;i<=n;++i) a[i]=read(),G[i].clear(); for (register int i=0;i<m;++i) { int u=read(),v=read(),type=read(); adde(u,v); if (type^1) adde(v,u); } for (register int i=1;i<=n;++i) if (!dfn[i]) dfs(i); for (int p=1;p<=n;++p) for (int i=head[p];~i;i=e[i].nxt) { int v=e[i].v; if (bel[v]^bel[p]) G[bel[p]].push_back(bel[v]); } for (int i=1;i<=scc;++i) f[i]=mx[i]-mn[i]; printf("%d\n",bfs()); return 0;}
阅读全文
0 0
- Luogu 1074(tarjan+dp)
- Luogu 3387(tarjan+dp)(tarjan+SPFA)
- Luogu 2661(tarjan)
- Luogu 1280(dp)
- Luogu 1282(dp)
- Luogu 1387(dp)
- Luogu 1156(dp)
- Luogu 1141(dp)
- Luogu 1880(区间dp)
- Luogu 1351(树形dp)
- Luogu 1040(区间dp)
- Luogu 1144(SPFA+dp)
- Luogu 2679(dp)(NOIP 2015)
- Luogu-P1025数的划分(dp)
- Luogu-P1057传球游戏(dp)
- Luogu 1273(树形dp)(背包dp)
- luogu p1122 DP
- luogu p3399 DP
- eclipse 异常断点和条件断点
- mybatis在xml文件中处理大于号小于号的方法
- Android发送权限受限的广播,指定接受方!
- 机器学习的分类及各自特点
- 彻底删除R Studio残留数据,全新重装R
- Luogu 1074(tarjan+dp)
- Spark核心RDD:combineByKey函数详解
- RecyclerView原理分析
- 一款好用的蓝牙键盘–罗技K38
- 重新编译jt.jar
- ReactiveCocoa Unknown warning group ‘-Wreceiver-is-weak’,ignored警告
- 十月随想录
- PHP运行原理
- java递归的应用和实例