【SEERC2022】 K.Knowledge Testing Problem 【整体二分】【最短路】
分析:注意到$|u-v|<=10$,所以可以将询问的最短路分类为,左边的最短路,跨越左右的最短路,右边的最短路。套整体二分的板子就行。以前应该做过
代码:
#include<bits/stdc++.h> using namespace std; const int maxn = 102000; typedef pair<long long,int> pr; int n,m,qy; struct node{ int to,w; }; struct query{ int u,v,pos; }q[maxn],nq[maxn]; vector<node> g[maxn]; long long dis[12][maxn]; int vis[maxn]; long long ans[maxn]; priority_queue<pr,vector<pr>,greater<pr> > pq; void dijkstra(int s,long long *dist,int l,int r){ for(int i=l;i<=r;i++) dist[i] = 1e17,vis[i] = 0; dist[s] = 0; pq.push(make_pair(0,s)); while(!pq.empty()){ pr k = pq.top();pq.pop(); if(vis[k.second]) continue; vis[k.second] = 1; for(auto x:g[k.second]){ if(dist[x.to] > dist[k.second]+x.w){ dist[x.to] = dist[k.second]+x.w; pq.push(make_pair(dist[x.to],x.to)); } } } } void Divide(int l,int r,int ql,int qr){ if(ql > qr) return; if(r-l <= 10){ for(int i=l;i<=r;i++){ dijkstra(i,dis[i-l],l,r); } for(int i=ql;i<=qr;i++){ int pos = q[i].pos; for(int j=0;j<=r-l;j++){ ans[pos]=min(ans[pos],dis[q[i].u-l][q[i].v]); } } }else{ int mid = (l+r)/2; int fl = mid-5,fr = mid+5; for(int i=fl;i<=fr;i++){ dijkstra(i,dis[i-fl],l,r); //range in [fl,r] source is i, load in i-fl } for(int i=l;i<fl;i++){ for(int j=0;j<g[i].size();j++){ if(g[i][j].to >= fl){ swap(g[i][j],g[i][g[i].size()-1]); g[i].pop_back(); j--; } } } for(int i=fl;i<=fr;i++) g[i].clear(); for(int i=fr+1;i<=r;i++){ for(int j=0;j<g[i].size();j++){ if(g[i][j].to <= fr){ swap(g[i][j],g[i][g[i].size()-1]); g[i].pop_back(); j--; } } } int dl=ql-1,dr=qr+1; for(int i=ql;i<=qr;i++){ for(int j=fl;j<=fr;j++){ ans[q[i].pos] = min(ans[q[i].pos],dis[j-fl][q[i].u]+dis[j-fl][q[i].v]); } if(q[i].v < fl) nq[++dl] = q[i]; if(q[i].u > fr) nq[--dr] = q[i]; } for(int i=ql;i<=qr;i++) q[i] = nq[i]; Divide(l,fl-1,ql,dl); Divide(fr+1,r,dr,qr); } } int main(){ ios::sync_with_stdio(false); cin.tie(0); cout.tie(0); cin >> n >> m >> qy; memset(ans,127/3,sizeof(ans)); for(int i=1;i<=m;i++){ int u,v,w; cin >> u >> v >> w; g[u].push_back((node){v,w}); g[v].push_back((node){u,w}); } for(int i=1;i<=qy;i++) { cin >> q[i].u >> q[i].v; if(q[i].u > q[i].v) swap(q[i].u,q[i].v); q[i].pos = i; } Divide(1,n,1,qy); for(int i=1;i<=qy;i++){ if(ans[i] > 1e15) cout<<"-1\n"; else cout<<ans[i]<<"\n"; } return 0; }