Solution
这题在暑假就讲了,等模拟赛出了还没做,只能亡羊补牢( ̄▽ ̄)"
先考虑如果指定经过一条边的最短路怎么求?
设此边为 ((u, v)) ,那么考虑从 (1) 和 (n) 开始分别跑两次最短路 。设 (disS_i) 为 (1) 到 (i) 的最短路, (disT) 同理,那么答案就是 (min(disS_u+dis_{u,v}+disT_{v},disS_v+dis_{u,v}+disT_{u}))
现在把修改分成4种:
- 修改的边不在 (1) 到 (n) 的最短路上,边的长度变大了
- 修改的边不在 (1) 到 (n) 的最短路上,边的长度变小了
- 修改的边在 (1) 到 (n) 的最短路上,边的长度变小了
- 修改的边在 (1) 到 (n) 的最短路上,边的长度变大了
可得原最短路长度为 (disS_n) ,设修改的边为 ((u,v)) ,对于1, (disS_n) 就是答案;对于2,那么答案就是 (min{disS_n,disS_u+dis_{u,v}+disT_{v},disS_v+dis_{u,v}+disT_{u}}) ;对于3,答案是 (disS_n-dis_{u,v}+w) ;
但是对于4,我们要进一步讨论。
设最短路为 (G) ,则路径上的边为 (G_1,G_2,G_3,cdots ,G_k) 。
对于每个不是 (G) 上的点, (1) 到 (u) 的最短路必定会经过一段 (G) 的前缀(可以为空)。设 (L_u) 表示这个前缀,那么 (disS_u) 经过 (G_1.G_2,cdots G_{L_u}) 。
对于 (u) 到 (n) 的最短路同理,可以得到 (R_u) 表示的后缀。
回到问题4,就是求 (min(disS_n-dis_{u,v}+w,不经过修改这条边的最短路长度)) 。
那么怎么快速求出不经过 (G) 上某条边的最短路长度呢?
我们可以使用线段树,区间 ((l,r)) 表示不经过 (G_l,cdots ,G_r) 这段的最短路长度。
而此时 (L,R) 的用处就来了,我们可以拿经过 ((u,v)) 这条边的最短路长度更新 ((L_u+1,R_v),(L_v+1,R_u)) 。
时间复杂度: (O(nlog n+mlog n+qlog n))
#include<bits/stdc++.h>
#define ll long long
#define ls rt<<1
#define rs rt<<1|1
using namespace std;
const int N=2e5+10,M=2e5+10;
const ll INF=1e18;
struct id_edge{
int u,v;
ll w;
}ie[M<<1];
int n,m,q,dist;
int in_dist[N],l[N],r[N];
bool road[N];
template <typename T> void read(T &x){
int f=1;x=0;
char ch=getchar();
while(!isdigit(ch)){if(ch=='-') f=-1;ch=getchar();}
while(isdigit(ch)){x=x*10+(ch^48);ch=getchar();}
x*=f;
}
struct edge{
int to,nxt,id;
ll w;
}e[M<<1];
int head[N],cnt;
inline void add(int id,int u,int v,ll w){
e[++cnt].to=v;
e[cnt].id=id;
e[cnt].w=w;
e[cnt].nxt=head[u];
head[u]=cnt;
}
int lst_vis[N];
ll dis_S[N],dis_T[N];
struct node{
int pos;
ll dis;
inline bool operator < (const node &x) const {
return x.dis<dis;
}
};
priority_queue<node> pq;
inline void dijkstral(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 x=pq.top();pq.pop();
int u=x.pos;
if(x.dis>dis[u]) continue;
for(int i=head[u];i;i=e[i].nxt){
int v=e[i].to;
if(dis[v]>x.dis+e[i].w){
lst_vis[v]=e[i].id;
dis[v]=x.dis+e[i].w;
if(f==1&&!road[v]) l[v]=l[u];
if(f==2&&!road[v]) r[v]=r[u];
pq.push(node{v,dis[v]});
}
}
}
}
inline void init_dist(){
int now=1;
road[now]=true;
l[now]=r[now]=0;
for(int i=1;now!=n;i++){
int now_id=lst_vis[now];
in_dist[now_id]=i;
++dist;
now=ie[now_id].u^ie[now_id].v^now;
road[now]=true;
l[now]=r[now]=i;
}
}
ll minn_dis[N<<4];
void build(int rt,int l,int r){
minn_dis[rt]=INF;
if(l==r) return ;
int mid=(l+r)>>1;
build(ls,l,mid);build(rs,mid+1,r);
}
void update(int rt,int l,int r,int L,int R,ll k){
if(L>R) return ;
if(L<=l&&r<=R){
minn_dis[rt]=min(minn_dis[rt],k);
return ;
}
int mid=(l+r)>>1;
if(L<=mid) update(ls,l,mid,L,R,k);
if(R>mid) update(rs,mid+1,r,L,R,k);
}
ll query(int rt,int l,int r,int x){
if(l==r) return minn_dis[rt];
int mid=(l+r)>>1;
ll res=minn_dis[rt];
if(x<=mid) res=min(res,query(ls,l,mid,x));
else res=min(res,query(rs,mid+1,r,x));
return res;
}
int main(){
// freopen("fee.in","r",stdin);
// freopen("fee.out","w",stdout);
read(n);read(m);read(q);
for(int i=1;i<=m;i++){
read(ie[i].u);read(ie[i].v);read(ie[i].w);
add(i,ie[i].u,ie[i].v,ie[i].w);add(i,ie[i].v,ie[i].u,ie[i].w);
in_dist[i]=-1;
}
dijkstral(n,dis_T);
init_dist();
dijkstral(1,dis_S,1);
dijkstral(n,dis_T,2);
build(1,1,dist);
for(int i=1;i<=m;i++)
if(in_dist[i]==-1){
update(1,1,dist,l[ie[i].u]+1,r[ie[i].v],dis_S[ie[i].u]+ie[i].w+dis_T[ie[i].v]);
update(1,1,dist,l[ie[i].v]+1,r[ie[i].u],dis_S[ie[i].v]+ie[i].w+dis_T[ie[i].u]);
}
for(int i=1,id,x;i<=q;i++){
read(id);read(x);
ll ans=dis_S[n];
if(in_dist[id]==-1){
if(x<ie[id].w){
ans=min(ans,dis_S[ie[id].u]+x+dis_T[ie[id].v]);
ans=min(ans,dis_S[ie[id].v]+x+dis_T[ie[id].u]);
}
}
else{
ans=ans-ie[id].w+x;
if(x>ie[id].w){
ans=min(ans,query(1,1,dist,in_dist[id]));
}
}
printf("%lld
",ans);
}
return 0;
}