正题
题目链接:https://www.cometoj.com/contest/73/problem/E?problem_id=4124
题目大意
给出nnn个点mmm条边的一张有向图,边有边权,qqq次询问从点111走到点xxx的所有路径(可以重复经过任何点包括点xxx)中极差最大是多少。
1≤n≤2×105,1≤m≤5×1051\leq n\leq 2\times 10^5,1\leq m\leq 5\times 10^51≤n≤2×105,1≤m≤5×105
解题思路
首先肯定要tarjantarjantarjan缩点,然后考虑怎么统计极差。
考虑到极差其实到某个位置的时候就已经不会再改变了,而且这个到这个位置的路径一定是作为最小值或者最大值的。
所以我们可以维护一个路径上的最大值/最小值和最大极差,然后每次考虑新的转移会不会更新极差就可以了。
时间复杂度:O(n+m)O(n+m)O(n+m)
CometOJ评测机炸了,代码没测就当过了吧…
code
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
#include<queue>
#include<stack>
#define mp(x,y) make_pair(x,y)
using namespace std;
const int N=2e5+10;
int n,m,t,cnt,dfn[N],low[N],col[N],in[N];
int mi[N],mx[N],Mi[N],Mx[N],ans[N];
stack<int> s;queue<int> q;bool ins[N];
vector<pair<int,int> > G[N],T[N];
void tarjan(int x){dfn[x]=low[x]=++cnt;ins[x]=1;s.push(x);for(int i=0;i<G[x].size();i++){int y=G[x][i].first;if(!dfn[y]){tarjan(y);low[x]=min(low[x],low[y]);}else if(ins[y])low[x]=min(low[x],dfn[y]);}if(dfn[x]==low[x]){while(s.top()!=x){col[s.top()]=x;ins[s.top()]=0;s.pop();}col[x]=x;ins[x]=0;s.pop();}return;
}
void Topsort(){for(int i=1;i<=n;i++)if(!in[i])q.push(i);while(!q.empty()){int x=q.front();q.pop();Mx[x]=max(Mx[x],mx[x]);Mi[x]=min(Mi[x],mi[x]);ans[x]=max(ans[x],mx[x]-Mi[x]);ans[x]=max(ans[x],Mx[x]-mi[x]);for(int i=0;i<T[x].size();i++){int y=T[x][i].first,w=T[x][i].second;in[y]--;Mx[y]=max(Mx[y],max(Mx[x],w));Mi[y]=min(Mi[y],min(Mi[x],w));ans[y]=max(ans[y],ans[x]);ans[y]=max(ans[y],w-Mi[x]);ans[y]=max(ans[y],Mx[x]-w);if(!in[y])q.push(y);}}return;
}
int main()
{scanf("%d%d%d",&n,&m,&t);for(int i=1;i<=m;i++){int x,y,w;scanf("%d%d%d",&x,&y,&w);G[x].push_back(mp(y,w));}tarjan(1);memset(mi,0x3f,sizeof(mi));memset(Mi,0x3f,sizeof(Mi));for(int x=1;x<=n;x++){for(int i=0;i<G[x].size();i++){int y=G[x][i].first,w=G[x][i].second;y=col[y];if(col[x]==y)mx[y]=max(mx[y],w),mi[y]=min(mi[y],w);else T[col[x]].push_back(mp(y,w)),in[y]++;}}Topsort();while(t--){int x;scanf("%d",&x);if(x==1||!col[x])puts("-1");else printf("%d\n",ans[col[x]]);}return 0;
}