傳送門
文章目錄
題意:
給你一個聯通無向圖,每條邊有一個長度lll和海拔aaa,當海拔≤\le≤水位線的時候,說明這個道有積水。在起始點有一輛車,車可以走沒有積水的路,下車后可以走有積水的路,下車后不能再上車?,F在有qqq個詢問,每次給一個起點vvv和水位線ppp,問從vvv到111號點的最小走路的距離是多少。
思路:
一發a還是很爽的。
轉換一下,就是從所有只能走a>pa> pa>p的邊能到的點,到111的最短路是多少。對于前一個,我們可以按照aaa從大到小排序,讓后倍增得到一顆子樹內所有點即為能到的點,讓后從111跑最短路預處理一下,之后dfsdfsdfs過程中記錄一下這個點為根的所有點中最短路的最小值即可。
#include<cstdio>
#include<iostream>
#include<string>
#include<cstring>
#include<map>
#include<cmath>
#include<cctype>
#include<vector>
#include<set>
#include<queue>
#include<algorithm>
#include<sstream>
#include<ctime>
#include<cstdlib>
#define X first
#define Y second
#define L (u<<1)
#define R (u<<1|1)
#define pb push_back
#define mk make_pair
#define Mid (tr[u].l+tr[u].r>>1)
#define Len(u) (tr[u].r-tr[u].l+1)
#define random(a,b) ((a)+rand()%((b)-(a)+1))
#define db puts("---")
using namespace std
;
typedef long long LL
;
typedef unsigned long long ULL
;
typedef pair
<int,int> PII
;const int N
=800010,mod
=1e9+7,INF
=0x3f3f3f3f;
const double eps
=1e-6;int n
,m
,q
,k
,s
;
int val
[N
],p
[N
],fa
[N
][20];
int e
[N
],ne
[N
],w
[N
],h
[N
],idx
;
int dis
[N
],st
[N
],mi
[N
];
vector
<int>v
[N
];
struct Edge
{int a
,b
,w
,h
;bool operator < (const Edge
&W
) const {return h
>W
.h
;}
}edge
[N
];void add(int a
,int b
,int c
)
{e
[idx
]=b
,w
[idx
]=c
,ne
[idx
]=h
[a
],h
[a
]=idx
++;
}void init()
{idx
=0;for(int i
=1;i
<=n
*2;i
++) h
[i
]=-1,p
[i
]=i
,dis
[i
]=INF
,st
[i
]=false,v
[i
].clear(),mi
[i
]=INF
;
}void dijkstra()
{priority_queue
<PII
,vector
<PII
>,greater
<PII
>>q
;dis
[1]=0; q
.push({0,1});while(q
.size()){PII t
=q
.top(); q
.pop();int u
=t
.Y
,d
=t
.X
;if(st
[u
]) continue;st
[u
]=1;for(int i
=h
[u
];~i
;i
=ne
[i
]){int ver
=e
[i
];if(dis
[ver
]>dis
[u
]+w
[i
]){dis
[ver
]=dis
[u
]+w
[i
];q
.push({dis
[ver
],ver
});}}}
}int find(int x
)
{return x
==p
[x
]? x
:p
[x
]=find(p
[x
]);
}void dfs(int u
,int f
)
{fa
[u
][0]=f
; mi
[u
]=min(mi
[u
],dis
[u
]);for(int i
=1;i
<=18;i
++) fa
[u
][i
]=fa
[fa
[u
][i
-1]][i
-1];for(auto x
:v
[u
]) dfs(x
,u
),mi
[u
]=min(mi
[u
],mi
[x
]);
}void exkruskal()
{sort(edge
+1,edge
+1+m
);for(int i
=1,tot
=n
;i
<=m
;i
++){int a
=edge
[i
].a
,b
=edge
[i
].b
,h
=edge
[i
].h
;int pa
=find(a
),pb
=find(b
);if(pa
==pb
) continue;p
[pa
]=p
[pb
]=++tot
;v
[tot
].pb(pa
); v
[tot
].pb(pb
);val
[tot
]=h
;}dfs(n
*2-1,0);
}int main()
{
int _
; scanf("%d",&_
);while(_
--){scanf("%d%d",&n
,&m
);init();for(int i
=1;i
<=m
;i
++){int a
,b
,w
,h
; scanf("%d%d%d%d",&a
,&b
,&w
,&h
);edge
[i
]={a
,b
,w
,h
}; add(a
,b
,w
); add(b
,a
,w
);}dijkstra(); exkruskal();scanf("%d%d%d",&q
,&k
,&s
);int ans
=0;val
[0]=0;while(q
--){int v
,p
; scanf("%d%d",&v
,&p
);v
=(v
+k
*ans
-1)%n
+1;p
=(p
+k
*ans
)%(s
+1);for(int i
=18;i
>=0;i
--) if(val
[fa
[v
][i
]]>p
) v
=fa
[v
][i
];printf("%d\n",ans
=mi
[v
]);}}return 0;
}
總結
以上是生活随笔為你收集整理的P4768 [NOI2018] 归程 Kruskal重构树 + 倍增 + 最短路的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。