給定一張無向圖, 每條邊有一個距離和一個高度. 再給定 \(q\) 組可能在線的詢問, 每組詢問給定一個點 \(v\) 和一個高度 \(h\), 鴨子德能夠先無需花費地在高度大於 \(h\) 的邊上任意行動, 而後能夠在任意點開始以花費等於距離的模式行動. 問最小的花費.php
\(|V|\le 2\times 10^5,|E|\le 4\times 10^5,q\le 4\times 10^5,h\le 10^9\).c++
顯然帶花費部分的行動是一個單源最短路. 那麼咱們只要求出無花費部分的行動能夠到達的點中哪個點距離 \(1\) 最近就能夠了.git
發現無花費部分是個相似瓶頸路的問題, 咱們能夠在 Kruskal 重構樹上倍增求出能到達的點所組成的子樹, 輸出這個子樹中的點到 \(1\) 的最短距離就能夠了.spa
爲啥我要寫這個裸題的題解呢?code
一個緣由是存板子, 另外一個緣由是這個沙雕強制在線把我卡掉了 \(3\) 分qaq...具體狀況blog
#include <bits/stdc++.h> const int MAXV=4e5+10; const int MAXE=1e6+10; struct Edge{ int from; int to; int dis; int pos; Edge* next; bool friend operator>(const Edge& a,const Edge& b){ return a.pos>b.pos; } }; Edge E[MAXE]; Edge Ex[MAXE]; Edge* head[MAXV]; Edge* top=E; int v; int e; int q; int n; int k; int maxv; int dis[MAXV]; int pos[MAXV]; int ufs[MAXV]; bool vis[MAXV]; int pprt[20][MAXV]; int* prt=pprt[0]; int ReadInt(); void Kruskal(); int FindRoot(int); void Dijkstra(int); void Insert(int,int,int,int); int main(){ int T=ReadInt(); while(T--){ memset(pprt,0,sizeof(pprt)); memset(head,0,sizeof(head)); memset(vis,0,sizeof(vis)); top=E; n=v=ReadInt(); e=ReadInt(); for(int i=0;i<e;i++){ int a=ReadInt(),b=ReadInt(),c=ReadInt(),d=ReadInt(); Ex[i]=Edge({a,b,c,d,NULL}); Insert(a,b,c,d); Insert(b,a,c,d); } q=ReadInt(),k=ReadInt(),maxv=ReadInt(); Dijkstra(1); Kruskal(); int lg=0; for(int i=1;(1<<i)<=v;i++){ lg=i; for(int j=1;j<=v;j++) pprt[i][j]=pprt[i-1][pprt[i-1][j]]; } int lastans=0; while(q--){ int s=(0ll+ReadInt()+k*lastans-1)%n+1,h=(0ll+ReadInt()+k*lastans)%(maxv+1); for(int i=lg;i>=0;i--){ if(pos[pprt[i][s]]>h) s=pprt[i][s]; } printf("%d\n",lastans=dis[s]); } } return 0; } void Kruskal(){ std::sort(Ex,Ex+e,std::greater<Edge>()); for(int i=1;i<=v;i++) ufs[i]=i; int& cur=v; for(int i=0;i<e;i++){ int a=FindRoot(Ex[i].from); int b=FindRoot(Ex[i].to); if(a!=b){ ++cur; pos[cur]=Ex[i].pos; dis[cur]=std::min(dis[a],dis[b]); prt[a]=cur; prt[b]=cur; ufs[cur]=cur; ufs[a]=cur; ufs[b]=cur; } } } void Dijkstra(int s){ std::priority_queue<std::pair<int,int>> q; memset(dis,0x7F,sizeof(dis)); dis[s]=0; q.emplace(0,s); while(!q.empty()){ s=q.top().second; q.pop(); if(vis[s]) continue; vis[s]=true; for(Edge* i=head[s];i!=NULL;i=i->next){ if(dis[i->to]>dis[s]+i->dis){ dis[i->to]=dis[s]+i->dis; q.emplace(-dis[i->to],i->to); } } } } inline void Insert(int from,int to,int dis,int pos){ top->from=from; top->to=to; top->dis=dis; top->pos=pos; top->next=head[from]; head[from]=top++; } int FindRoot(int x){ return ufs[x]==x?ufs[x]:ufs[x]=FindRoot(ufs[x]); } inline int ReadInt(){ int x=0; register char ch=getchar(); while(!isdigit(ch)) ch=getchar(); while(isdigit(ch)){ x=x*10+ch-'0'; ch=getchar(); } return x; }