2018.10.23【校內模擬】“新”的家園(最短路)(玄學建圖)
阿新 • • 發佈:2018-12-17
傳送門
解析:
首先我們是不能直接在原圖上直接跑最短路的,時間肯定爆炸。(廢話)
我們注意一個性質,環外邊最多隻有300,第一種情況不管,反正只有一組詢問。
那麼這三百條邊最多會連線600個節點。這些點我們稱為關鍵點,這些邊稱為關鍵邊。 可以發現,除了環上距離,能夠更新兩點之間的最短路的只有關鍵邊。
那麼考慮原來的環上相鄰兩個關鍵點之間的那些點。顯然,當所求最短路的起始點不在這些點中時,這些點的更新只會拖慢求最短路的進度,就是拖延收斂時間。
那麼我們考慮把這些點去掉,只保留關鍵點,保留關鍵點之間的關建邊,同時關鍵點之間連權值為原來環上距離的邊。
那麼我們每次就只在簡略後的圖上面跑最短路,只需要把我們要求的加回原圖,與原來相鄰的關鍵點連距離為環上距離的邊。顯然,新圖上的距離仍然符合原圖的情況,求出來的最短路顯然也是原圖的最短路。
注意一點,我們必須在求完最短路後刪去新增的點和邊,不然複雜度顯然會逐漸增大,直到最後無法承受。
刪邊其實很簡單,我們只需要用前向星記錄一下邊,新增的邊顯然在前向星的末尾,直接刪去就好了。
注意求的有可能本來就是不需要經過關鍵點的最短路,所以加邊的時候需要直接加一條的環上距離的邊。
還有就是其實點數很小,所以我們可以承受跑那麼多次最短路,無所畏懼。
而且這是一個同階的稀疏圖,所以不會被卡,且表現優於。
最後一點,我們不能很方便的維護環上距離,所以直接斷環成鏈,強行令這條邊為特殊邊。維護所有節點到的鏈上距離,其他的直接差分就好了。
程式碼:
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define re register
#define gc getchar
#define pc putchar
#define cs const
inline int getint(){
re int num;
re char c;
while(!isdigit(c=gc()));num=c^48;
while(isdigit(c=gc()))num=(num<<1)+(num<<3)+(c^48);
return num;
}
inline void outint(int a){
static char ch[23];
if(a==0)pc('0');
while(a)ch[++ch[0]]=a-a/10*10,a/=10;
while(ch[0])pc(ch[ch[0]--]^48);
}
cs int N=500005,M=2000006,INF=0x3f3f3f3f;
bool iskey[N];
int head[N];
int last[N],nxt[M<<1],to[M<<1],ecnt;
int w[M<<1];
inline void addedge(int u,int v,int val){
assert(val>=0);
nxt[++ecnt]=last[u],last[u]=ecnt,to[ecnt]=v,w[ecnt]=val;
nxt[++ecnt]=last[v],last[v]=ecnt,to[ecnt]=u,w[ecnt]=val;
}
int top,sta[N];
int Ecnt;
inline void clear(){
ecnt=Ecnt;
while(top){
last[sta[top]]=head[sta[top]];
--top;
}
}
int pt[N],pcnt;
int sum[N];
inline void ins(int s){
if(iskey[s])return ;
for(int re i=1;i<=pcnt;++i){
if(pt[i]<s&&pt[i+1]>s){
sta[++top]=s;
sta[++top]=pt[i];
sta[++top]=pt[i+1];
addedge(s,pt[i],sum[s]-sum[pt[i]]);
addedge(s,pt[i+1],sum[pt[i+1]]-sum[s]);
return ;
}
}
}
bool vis[N];
int dist[N];
queue<int > q;
inline int SPFA(int s,int t){
if(s==t)return 0;
for(int re i=1;i<=pcnt;++i)dist[pt[i]]=INF;
dist[s]=0;dist[t]=INF;
q.push(s);
while(!q.empty()){
int u=q.front();
q.pop();
vis[u]=false;
for(int re e=last[u],v=to[e];e;v=to[e=nxt[e]]){
if(dist[v]>dist[u]+w[e]){
dist[v]=dist[u]+w[e];
if(vis[v])continue;
vis[v]=true;
q.push(v);
}
}
}
return dist[t];
}
int n,m,Q;
signed main(){
memset(sum,0x3f,sizeof sum);
n=getint();
m=getint();
Q=getint();
for(int re i=1;i<=m;++i){
int u=getint(),v=getint(),val=getint();
if(u>v)swap(u,v);
if(u+1!=v){
iskey[u]=iskey[v]=true;
addedge(u,v,val);
}
else sum[v]=min(sum[v],val);
}
sum[0]=sum[1]=0;
for(int re i=1;i<=n;++i)sum[i]+=sum[i-1];
for(int re i=1;i<=n;++i){
static int last=0;
if(iskey[i]){
pt[++pcnt]=i;
if(!last){
last=i;
continue;
}
addedge(last,i,sum[i]-sum[last]);
last=i;
}
}
Ecnt=ecnt;
memcpy(head,last,sizeof last);
while(Q--){
clear();
int s=getint(),t=getint();
if(s>t)swap(s,t);
addedge(s,t,sum[t]-sum[s]);
sta[++top]=s;sta[++top]=t;
ins(s);ins(t);
outint(SPFA(s,t));
pc('\n');
}
return 0;
}