題目大意
n點m邊無向圖,k個關鍵點,q個詢問(a,b)。問從a到b需要的最小容量c是多少。保證a,b是關鍵點。你能量池最多有c能量,每次走邊消耗邊權那麼多的能量。在關鍵點會補滿能量。每次詢問需要的最少能量。
解題思路
以所有關鍵點爲源求一遍多源最短路,然後對於一個點,如果當前能量,肯定到不了,如果,那麼應該是的。又因爲所以可以跑到那個最近的關鍵點又回來,所以x每個點u的能量可以保持在。可以走需要,轉換成。以爲新邊權建立新圖。
問題就變成從一個點到另一個點經過的路徑上的最大值最小可以是多少。
兩種做法:
1.離線做法 把邊按權值排序之後進行並查集。詢問掛在點上。按需要處理的詢問數量進行啓發式合併,每個詢問最多移動次
2.在線做法 建立 Kruskal樹之後進行樹上倍增求lca的點權
離線做法:
#include<bits/stdc++.h>
#define ll long long
#define lowbit(x) ((x)&(-(x)))
#define mid ((l+r)>>1)
#define lson rt<<1, l, mid
#define rson rt<<1|1, mid+1, r
#define P pair<ll, int>
using namespace std;
const int maxn = 3e5 + 50;
struct edge{
int u ,v , nxt;
ll w;
bool operator < (const edge &a)const{return w < a.w;}
}e[maxn*2];
int cnt = 0;
int head[maxn];
void add(int u, int v, ll w){
e[cnt] = (edge){u, v, head[u], w};
head[u] = cnt++;
}
int n, m, k, Q;
priority_queue<P, vector<P>, greater<P> > q;
ll dis[maxn];
void dij(){
while(q.size()){
P temp = q.top();q.pop();
int u = temp.second;
if(dis[u] < temp.first) continue;
for(int i = head[u]; ~i; i = e[i].nxt){
int v = e[i].v; ll w = e[i].w;
if(dis[v] > dis[u] + w){
dis[v] = dis[u] + w;
q.push(P(dis[v], v));
}
}
}
}
void init(){
memset(head, -1, sizeof head);
cin>>n>>m>>k>>Q;
for(int i = 0; i < m; ++i){
int u, v; ll w; scanf("%d%d%lld", &u, &v, &w);
add(u, v, w); add(v, u, w);
}
memset(dis, 0x3f, sizeof dis);
for(int i = 1; i <= k; ++i){
dis[i] = 0; q.push(P(0, i));
}dij();
int tp = 0;
for(int i = 0; i < cnt; i += 2){
e[tp] = e[i];
e[tp++].w += dis[e[i].u]+dis[e[i].v];
}
cnt = tp;
}
ll ans[maxn*5];
struct node{int v, id;};
vector<node> g[maxn];
int fa[maxn];
int fnd(int x){
if(x == fa[x]) return x;
return fa[x] = fnd(fa[x]);
}
void link(int u, int v, ll w){
u = fnd(u); v = fnd(v);
if(u == v) return;
if(g[u].size() > g[v].size()) swap(u, v);
for(int i = 0; i < g[u].size(); ++i){
int x = g[u][i].v;
int id = g[u][i].id;
if(fnd(x) == v)
ans[id] = w;
else
g[v].push_back(g[u][i]);
}
fa[u] = v;
g[u].clear();//g[u].shrink_to_fit(); return;
}
void sol(){
for(int i = 1; i <= n; ++i) fa[i] = i;
for(int i = 0; i < Q; ++i){
int u, v;
scanf("%d%d", &u, &v);
g[u].push_back((node){v, i});
g[v].push_back((node){u, i});
}
sort(e, e+cnt);
for(int i = 0; i < cnt; ++i) link(e[i].u, e[i].v, e[i].w);
for(int i = 0; i < Q; ++i) {
printf("%lld\n", ans[i]);
}
}
int main()
{
init();
sol();
}
在線做法:
#include<bits/stdc++.h>
#define ll long long
#define lowbit(x) ((x)&(-(x)))
#define mid ((l+r)>>1)
#define lson rt<<1, l, mid
#define rson rt<<1|1, mid+1, r
#define P pair<ll, int>
using namespace std;
const int maxn = 3e5 + 50;
struct edge{
int u ,v , nxt;
ll w;
bool operator < (const edge &a)const{return w < a.w;}
}e[maxn*2];
int cnt = 0;
int head[maxn];
void add(int u, int v, ll w){
e[cnt] = (edge){u, v, head[u], w};
head[u] = cnt++;
}
int n, m, k, Q;
priority_queue<P, vector<P>, greater<P> > q;
ll dis[maxn];
void dij(){
while(q.size()){
P temp = q.top();q.pop();
int u = temp.second;
if(dis[u] < temp.first) continue;
for(int i = head[u]; ~i; i = e[i].nxt){
int v = e[i].v; ll w = e[i].w;
if(dis[v] > dis[u] + w){
dis[v] = dis[u] + w;
q.push(P(dis[v], v));
}
}
}
}
void init(){
memset(head, -1, sizeof head);
cin>>n>>m>>k>>Q;
for(int i = 0; i < m; ++i){
int u, v; ll w; scanf("%d%d%lld", &u, &v, &w);
add(u, v, w); add(v, u, w);
}
memset(dis, 0x3f, sizeof dis);
for(int i = 1; i <= k; ++i){
dis[i] = 0; q.push(P(0, i));
}dij();
int tp = 0;
for(int i = 0; i < cnt; i += 2){
e[tp] = e[i];
e[tp++].w += dis[e[i].u]+dis[e[i].v];
}
cnt = tp;
}
ll ans[maxn];
int fa[maxn*2];
int fnd(int x){
if(x == fa[x]) return x;
return fa[x] = fnd(fa[x]);
}
int tot;
vector<int> g[maxn];
ll val[maxn];
int f[maxn][20], dep[maxn];
void get_mst(){
tot = n;
for(int i = 0; i <cnt; ++i){
int u = e[i].u; int v = e[i].v;
u = fnd(u); v = fnd(v); if(u == v) continue;
fa[u] = fa[v] = ++tot; fa[tot] = tot; val[tot] = e[i].w;
g[tot].push_back(v); f[v][0] = tot;
g[tot].push_back(u); f[u][0] = tot;
}
}
void dfs(int u){
for(int i = 0; i+1 < 20; ++i) f[u][i+1] = f[f[u][i]][i];
for(int i = 0; i < g[u].size(); ++i) dep[g[u][i]] =dep[u]+1, dfs(g[u][i]);
}
int lca(int u, int v){
if(dep[u] > dep[v]) swap(u, v);
int d = dep[v] - dep[u]; for(int i = 19; i >= 0; --i) if(d>>i&1) v = f[v][i];
if(u == v) return u;
for(int i = 19; i >= 0; --i){
if(f[u][i] == f[v][i]) continue;
u = f[u][i]; v = f[v][i];
}return f[u][0];
}
void sol(){
for(int i = 1; i <= n; ++i) fa[i] = i;
sort(e, e+cnt);
get_mst();
dfs(tot);
while(Q--){
int u, v; scanf("%d%d", &u, &v);
printf("%lld\n", val[lca(u,v)]);
}
}
int main()
{
init();
sol();
}