CF1163F Indecisive Taxi Fee

LIdox1536513344

2019-05-12 12:52:34

Solution

##### 题意简述 给你一个n个点,m条边的无向图,每条边连接点u、v,并且有个长度w。 有q次询问,每次询问给你一对t、x,表示仅当前询问下,将t这条边的长度修改为x,请你输出当前1到n的最短路长度。 数据范围 2 ≤ n ≤ 2e5 1 ≤ m, q ≤ 2e5 1 ≤ wi,xi ≤ 1e9 ### 题目分析 我们先不考虑修改,考虑给出指定的边,求出经过这条边的最短路 设这条边连接u,v,很容易想到这样的话只需要从1与n分别跑一遍Dijkstra,最短路长度就是 min(1到u的距离+边长+v到n的距离,1到v的距离+边长+u到n的距离)。 我们可以把修改分为以下几类: *1.修改的边在1到n的最短路上,边的长度变大了。 *2.修改的边在1到n的最短路上,边的长度变小了。 *3.修改的边不在1到n的最短路上,边的长度变大了。 *4.修改的边不在1到n的最短路上,边的长度变小了。 很容易知道: 对于*2, 原最短路长度-原边长+新边长 就是答案。 对于*3, 原最短路长度 就是答案。 对于*4, 由前面的思考得 min(原最短路长度,min(1到u的距离+新边长+v到n的距离,1到v的距离+新边长+u到n的距离) 就是答案。 都是O(1)得出答案 于是只剩下*1了。 对于原问题,我们可以得到一些简单的结论。 令原最短路为E,其路径为E1,E2,E3……Ek. 对于每个不是E上的点u,1到u的最短路必定会使用E的一段前缀(可以为空)。 令这个前缀为Lu,1到u的最短路经过E1,E2,……E(Lu)。 同理可得u到n的最短路必定会使用E的一段后缀(可以为空)。 令这个后缀为Ru,u到n的最短路经过E1,E2,……E(Ru)。 特别地,对于E上的点u,令其L为E上连接自己的边的编号,R为自己连到下一个E上点的边的编号 ##### 解法 关于如何求出每个点的L与R,我们可以先从n到1跑一遍Dijkstra,求出E的路径。 然后分别从1到n,n到1各跑一遍Dijkstra,过程中分别更新每个非E上点的L,R。 有了每个点的L,R后,考虑如何解决*1。 *1就是求min(E的长度-原边长+新边长,不经过修改的这条边的最短路长度) 问题从而转化成如何快速求出 不经过E上某条边的最短路长度 考虑使用线段树,树上的每段区间 l,r 的值表示 整个图不经过E上l到r这段的最短路长度 有了每个点的L,R我们很容易用图中非E上的边更新线段树 例如:一条边连接点u,v,经过这条边的最短路长度为len, 我们可以把树上 Lu+1,Rv 的区间用len更新,比个min, 同样地,可以把 Lv+1,Ru 的区间用len更新 **由于代码中点1的l,r为0,且l=r,所以l要加1 **如果图方便,可以把l[1]=1,r[1]=0,每个点的l比r大1 **不懂的话可以自己画图比划比划 从而我们可以在O(logn)的时间内回答每个问题 总的复杂度为O((m+n+q)logn) ```cpp #include<bits/stdc++.h> using namespace std; typedef long long ll; const int MAXN=2e5+5; const int MAXM=2e5+5; const ll Inf=1e18; struct Original_Edge{ int u,v;ll len; }oe[MAXM]; struct Node{ int pos; ll dis; inline bool operator<(const Node &x)const{ return x.dis<dis; } }; struct Edge{ int id,to,nxt; ll len; }e[MAXM<<1]; int cnt,head[MAXN]; inline void add_edge(int id,int u,int v,ll len){ e[++cnt].id=id;e[cnt].to=v;e[cnt].nxt=head[u];e[cnt].len=len;head[u]=cnt; } int n,m,q; int ind[MAXN]; int lstvis[MAXN]; int path_cnt,l[MAXN],r[MAXN]; bool On_path[MAXN]; ll disS[MAXN],disT[MAXN]; priority_queue<Node> pq; ll t[MAXM<<4]; inline void Dijkstra(int s,ll dis[],int f=0){ for(int i=1;i<=n;++i) dis[i]=Inf; dis[s]=0; pq.push((Node){s,0}); while(!pq.empty()){ Node fa=pq.top();pq.pop(); int x=fa.pos; if(fa.dis>dis[x]) continue; for(int i=head[x],y;i;i=e[i].nxt){ y=e[i].to; if(dis[y]>fa.dis+e[i].len){ lstvis[y]=e[i].id; dis[y]=fa.dis+e[i].len; if(f==1&&!On_path[y]) l[y]=l[x]; if(f==2&&!On_path[y]) r[y]=r[x]; pq.push((Node){y,dis[y]}); } } } } inline void Trace(){ On_path[1]=true; l[1]=r[1]=0; int cur=1; for(int i=1;cur!=n;++i){ int Edge_id=lstvis[cur]; ind[Edge_id]=i; ++path_cnt; cur=oe[Edge_id].u^oe[Edge_id].v^cur; On_path[cur]=true; l[cur]=r[cur]=i; } } inline void Build(int k,int l,int r){ t[k]=Inf; if(l==r) return; int mid=(l+r)>>1; Build(k<<1,l,mid); Build(k<<1|1,mid+1,r); } inline void Update(int k,int l,int r,int x,int y,ll v){ if(x>y) return; if(x<=l&&r<=y){ t[k]=min(t[k],v); return; } int mid=(l+r)>>1; if(x<=mid) Update(k<<1,l,mid,x,y,v); if(y>mid) Update(k<<1|1,mid+1,r,x,y,v); } inline ll Query(int k,int l,int r,int x){ if(l==r) return t[k]; int mid=(l+r)>>1; ll res=t[k]; if(x<=mid) res=min(res,Query(k<<1,l,mid,x)); else res=min(res,Query(k<<1|1,mid+1,r,x)); return res; } int main(){ ios::sync_with_stdio(0); cin>>n>>m>>q; for(int i=1;i<=m;++i){ cin>>oe[i].u>>oe[i].v>>oe[i].len; add_edge(i,oe[i].u,oe[i].v,oe[i].len); add_edge(i,oe[i].v,oe[i].u,oe[i].len); ind[i]=-1; } Dijkstra(n,disT); Trace(); Dijkstra(1,disS,1); Dijkstra(n,disT,2); Build(1,1,path_cnt); for(int i=1;i<=m;++i){ if(ind[i]==-1){ Update(1,1,path_cnt,l[oe[i].u]+1,r[oe[i].v],disS[oe[i].u]+oe[i].len+disT[oe[i].v]); Update(1,1,path_cnt,l[oe[i].v]+1,r[oe[i].u],disS[oe[i].v]+oe[i].len+disT[oe[i].u]); } } for(int i=1;i<=q;++i){ int Edge_id;ll New_len,ans=disS[n]; cin>>Edge_id>>New_len; if(ind[Edge_id]!=-1){ ans=disS[n]-oe[Edge_id].len+New_len; if(New_len>oe[Edge_id].len) ans=min(ans,Query(1,1,path_cnt,ind[Edge_id])); } else{ if(New_len<oe[Edge_id].len){ ans=min(ans,disS[oe[Edge_id].u]+New_len+disT[oe[Edge_id].v]); ans=min(ans,disS[oe[Edge_id].v]+New_len+disT[oe[Edge_id].u]); } } cout<<ans<<endl; } return 0; } ```