USACO JAN 09 Safe Travel G
[USACO09JAN] Safe Travel G
题面翻译
【题目描述】
给定一张有 个节点, 条边的无向图,对于任意的 (),请求出在不经过原来 节点到 节点最短路上最后一条边的前提下, 节点到 节点的最短路。
特别地,保证 到任何一个点 的最短路都是唯一的。
保证图中没有重边和自环。
【输入格式】
第一行,两个整数 。
之后 行,每行三个整数 表示有一条 到 ,边权为 的无向边。
【输出格式】
共 行,第 行表示 到 在不经过原来 节点到 节点最短路上最后一条边的前提下的最短路。如果最短路不存在,则在对应行输出 -1
。
翻译贡献者:@cryozwq。
题目描述
Gremlins have infested the farm. These nasty, ugly fairy-like
creatures thwart the cows as each one walks from the barn (conveniently located at pasture_1) to the other fields, with cow_i traveling to from pasture_1 to pasture_i. Each gremlin is personalized and knows the quickest path that cow_i normally takes to pasture_i. Gremlin_i waits for cow_i in the middle of the final cowpath of the quickest route to pasture_i, hoping to harass cow_i.
Each of the cows, of course, wishes not to be harassed and thus chooses an at least slightly different route from pasture_1 (the barn) to pasture_i.
Compute the best time to traverse each of these new not-quite-quickest routes that enable each cow_i that avoid gremlin_i who is located on the final cowpath of the quickest route from pasture_1 to
pasture_i.
As usual, the M (2 <= M <= 200,000) cowpaths conveniently numbered 1..M are bidirectional and enable travel to all N (3 <= N <= 100,000) pastures conveniently numbered 1..N. Cowpath i connects pastures a_i (1 <= a_i <= N) and b_i (1 <= b_i <= N) and requires t_i (1 <= t_i <= 1,000) time to traverse. No two cowpaths connect the same two pastures, and no path connects a pasture to itself (a_i != b_i). Best of all, the shortest path regularly taken by cow_i from pasture_1 to pasture_i is unique in all the test data supplied to your program.
By way of example, consider these pastures, cowpaths, and [times]:
1--[2]--2-------+ | | | [2] [1] [3] | | | +-------3--[4]--4
TRAVEL BEST ROUTE BEST TIME LAST PATH p_1 to p_2 1->2 2 1->2 p_1 to p_3 1->3 2 1->3 p_1 to p_4 1->2->4 5 2->4
When gremlins are present:
TRAVEL BEST ROUTE BEST TIME AVOID p_1 to p_2 1->3->2 3 1->2 p_1 to p_3 1->2->3 3 1->3 p_1 to p_4 1->3->4 6 2->4
For 20% of the test data, N <= 200.
For 50% of the test data, N <= 3000.
TIME LIMIT: 3 Seconds
MEMORY LIMIT: 64 MB
输入格式
* Line 1: Two space-separated integers: N and M
* Lines 2..M+1: Three space-separated integers: a_i, b_i, and t_i
输出格式
* Lines 1..N-1: Line i contains the smallest time required to travel from pasture_1 to pasture_i+1 while avoiding the final cowpath of the shortest path from pasture_1 to pasture_i+1. If no such path exists from pasture_1 to pasture_i+1, output -1 alone on the line.
样例 #1
样例输入 #1
4 5 1 2 2 1 3 2 3 4 4 3 2 1 2 4 3
样例输出 #1
3 3 6
提示
感谢 karlven 提供翻译。
分析
不妨先求出最短路树,由题可得,对于点 , 子树一点 ,子树外一点 ,路径 是合法的。
即 ,其中 为该非树边边权,其余皆为根到点的路径长。
可以在遍历时累加,于是将 看作一个整体,分别记在 中,每次取最小即可(没有则为-1)。
如图:
但是还有问题,一条非树边可能连接了 子树的两个节点,这时要去掉该非树边的贡献:
具体而言,在一条非树边两点对应的权值线段树上的 +1,在两点的lca 对应的权值线段树上的 -2。
然后遍历此树,向上合并权值线段树,合并完 子树的线段树后 的答案即为线段树中的最小值 - 。
即 = - (若为负数则无路径,输出-1即可)。
#include<bits/stdc++.h> using namespace std; typedef long long ll; const int N=2e5+100; const ll INF=1e12; struct edge { int x,y,n; ll z; bool operator < (const edge &a) const { return z>a.z; } }e[N<<1]; struct segtree { struct node { int lc,rc,val; }s[N<<6]; int tot; void upd(int &i,ll l,ll r,ll x,int z) { if(!i) i=++tot; s[i].val+=z; if(l==r) return ; ll mid=(l+r)>>1; if(x<=mid) upd(s[i].lc,l,mid,x,z); else upd(s[i].rc,mid+1,r,x,z); } void merg(int &i,int &j,ll l,ll r)//i <-- j { if(i==0 || j==0) { i+=j; return ; } if(l==r) { s[i].val+=s[j].val; return ; } ll mid=(l+r)>>1; merg(s[i].lc,s[j].lc,l,mid); merg(s[i].rc,s[j].rc,mid+1,r); s[i].val= s[ s[i].lc ].val + s[ s[i].rc ].val; } ll que(int i,ll l,ll r) { if(i==0) return 0; if(l==r) return l; ll sum=0; ll mid=(l+r)>>1; if(s[ s[i].lc ].val >0) sum=que(s[i].lc,l,mid); else sum=que(s[i].rc,mid+1,r); return sum; } }T; priority_queue<edge ,vector<edge> >q; vector<int >son[N]; int n,m,head[N],cnt=1,dfn; int deg[N],vis[N],pre[N],h[N]; int f[N][21],dep[N],root[N],st[N]; ll dis[N],ans[N]; void ad(int x,int y,ll z) { e[++cnt].n=head[x]; e[cnt].y=y; e[cnt].z=z; e[cnt].x=x; head[x]=cnt; } void init(); void loading(); void work(); void print(); int main() { init(); loading(); work(); return 0; } edge emp; edge made(int y,ll z) { emp.y=y; emp.z=z; return emp; } void dijk() { ++dfn; for(int i=1;i<=n;++i) { dis[i]=INF; ans[i]=-1; st[i]=i; } dis[1]=0; q.push( made(1,0) ); while(!q.empty()) { edge nw=q.top(); q.pop(); int u=nw.y; if(vis[u]==dfn) continue; vis[u]=dfn; for(int i=head[u],v;i;i=e[i].n) { v=e[i].y; if(dis[v]>dis[u]+e[i].z) { pre[v]=u; dis[v]=dis[u]+e[i].z; q.push( made(v,dis[v]) ); } } } } void init() { freopen("travel.in","r",stdin); freopen("travel.out","w",stdout); scanf("%d%d",&n,&m); for(int i=1,x,y;i<=m;++i) { ll z; scanf("%d%d%lld",&x,&y,&z); ad(x,y,z); ad(y,x,z); } } int fin(int x) { return (st[x]==x)?(x):(st[x]=fin(st[x])); } void go(int u) { int he=1,ta=0; while(vis[u]<dfn) { h[++ta]=u; u=pre[u]; } for(int i=ta,fa,x,fx,fy;i>=1;--i) { // h[i] --> h[i-1] x=h[i]; fa=pre[ x ]; fx=fin(x); fy=fin(fa); if(fx!=fy) st[fx]=fy; vis[ x ]=dfn; f[x][0]=fa; dep[x]=dep[fa]+1; ++deg[ fa ]; son[ fa ].push_back(x); for(int j=1;j<=19;++j) f[x][j]= f[ f[x][j-1] ][j-1]; } } int lca(int x,int y) { if(x==y) return x; if(dep[x]<dep[y]) swap(x,y); for(int i=19;i>=0;--i) if(dep[ f[x][i] ]>dep[y]) x=f[x][i]; if(dep[x]!=dep[y]) x=f[x][0]; if(x==y) return x; for(int i=19;i>=0;--i) if(f[x][i] != f[y][i]) { x=f[x][i]; y=f[y][i]; } return f[x][0]; } void loading() { dijk(); ++dfn; vis[1]=dfn; for(int i=2;i<=n;++i) if(vis[i]<dfn) go(i); } void gotans(int u) { for(int i=0,v;i<deg[u];++i) { v=son[u][i]; gotans(v); T.merg(root[u],root[v],1ll,INF); } ans[u]=T.que(root[u],1ll,INF)-dis[u]; } void work() { for(int i=2,x,y,z,lc;i<=cnt;++i) { x=e[i].x; y=e[i].y; z=e[i].z; if(f[x][0]==y || f[y][0]==x || ( fin(st[x])!=1 ) || ( fin(st[y])!=1 ) ) continue; lc=lca(x,y); //dis[x] + dis[y] +z int val=dis[x] + dis[y] +z; T.upd(root[x],1ll,INF,val,1); T.upd(root[y],1ll,INF,val,1); T.upd(root[lc],1ll,INF,val,-2); } gotans(1); print(); } void print() { for(int i=2;i<=n;++i) { printf("%d\n",(ans[i]<0)?(-1):(ans[i])); } }
本文来自博客园,作者:Glowingfire,转载请注明原文链接:https://www.cnblogs.com/Glowingfire/p/18634060
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 在鹅厂做java开发是什么体验
· 百万级群聊的设计实践
· WPF到Web的无缝过渡:英雄联盟客户端的OpenSilver迁移实战
· 永远不要相信用户的输入:从 SQL 注入攻防看输入验证的重要性
· 全网最简单!3分钟用满血DeepSeek R1开发一款AI智能客服,零代码轻松接入微信、公众号、小程