P4768-[NOI2018]归程【kruskal重构树,最短路】
生活随笔
收集整理的這篇文章主要介紹了
P4768-[NOI2018]归程【kruskal重构树,最短路】
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
正題
題目鏈接:https://www.luogu.com.cn/problem/P4768
題目大意
nnn個點mmm條邊的無向圖,然后每條邊有水位和長度。
每次詢問一個(v,w)(v,w)(v,w)表示從vvv點出發走高度超過www的路徑到達一個點xxx使得x~1x\sim1x~1的最短路最短。
解題思路
先用DijDijDij跑出111的單源最短路,然后邊權從大到小排序建立一顆KruskalKruskalKruskal重構樹,這樣的話如果一個權值為valvalval的點的子樹表示在這顆子樹中走權值大于valvalval的點的話這棵子樹中任意點之間可以相互到達。
所有我們每個點維護子樹中最小的最短路,然后對于詢問點用倍增跳到滿足條件的最上面的節點就好了。
codecodecode
#include<cstdio> #include<cstring> #include<algorithm> #include<queue> #define ll long long using namespace std; const ll N=800010; struct edge_node{ll x,y,w; }e[N]; struct node{ll to,next,w; }a[N]; struct point_node{ll pos,dis; }; bool operator<(point_node x,point_node y) {return x.dis>y.dis;} priority_queue<point_node> q; ll n,m,Q,k,s,cnt,tot,lastans,T; ll fa[N],f[N],g[N][25],val[N],ls[N]; bool v[N]; void addl(ll x,ll y,ll w) {a[++tot].to=y;a[tot].next=ls[x];ls[x]=tot;a[tot].w=w; } bool cmp(edge_node x,edge_node y) {return x.w>y.w;} void dij(){q.push((point_node){1,0});memset(v,0,sizeof(v));memset(f,127,sizeof(f));f[1]=0;while(!q.empty()){ll x=q.top().pos;q.pop();if(v[x]) continue;v[x]=1;for(ll i=ls[x];i;i=a[i].next){ll y=a[i].to;if(f[x]+a[i].w<f[y]){f[y]=f[x]+a[i].w;if(!v[y])q.push((point_node){y,f[y]});}}}return; } ll find(ll x) {return (x==fa[x])?x:(fa[x]=find(fa[x]));} void dfs(ll x) {for(ll i=ls[x];i;i=a[i].next){ll y=a[i].to;g[y][0]=x;dfs(y);f[x]=min(f[x],f[y]);} } ll up(ll x,ll p){for(ll i=24;i>=0;i--)if(val[g[x][i]]>p) x=g[x][i];return x; } void work() {scanf("%lld%lld",&n,&m);for(ll i=1;i<=m;i++){ll w;scanf("%lld%lld%lld%lld",&e[i].x,&e[i].y,&w,&e[i].w);addl(e[i].x,e[i].y,w);addl(e[i].y,e[i].x,w);}dij();tot=0;memset(ls,0,sizeof(ls));sort(e+1,e+1+m,cmp);for(ll i=1;i<=n+m;i++)fa[i]=i;cnt=n;for(ll i=1;i<=m;i++){ll fx=find(e[i].x),fy=find(e[i].y);if(fx!=fy){val[++cnt]=e[i].w;fa[fx]=cnt;fa[fy]=cnt;addl(cnt,fx,0);addl(cnt,fy,0);}}dfs(find(1));for(ll i=1;i<25;i++)for(ll j=1;j<=cnt;j++)g[j][i]=g[g[j][i-1]][i-1];scanf("%lld%lld%lld",&Q,&k,&s);lastans=0;while(Q--){ll v,p;scanf("%lld%lld",&v,&p);v=(v+k*lastans-1)%n+1;p=(p+k*lastans)%(s+1);printf("%lld\n",lastans=f[up(v,p)]);} } int main() {scanf("%lld",&T);while(T--){memset(ls,0,sizeof(ls));memset(val,0,sizeof(val));memset(g,0,sizeof(g));tot=0; work();} }總結
以上是生活随笔為你收集整理的P4768-[NOI2018]归程【kruskal重构树,最短路】的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 寄了是什么意思 寄了解释
- 下一篇: 初衷是什么意思 怎么理解初衷的意思