Plan de desplazamiento en H ZOJ-4001 (trayectoria mínima máxima, árbol de expansión mínimo)

A BaoBao le encanta viajar. Hay (N) ciudades marcadas en su mapa de viaje, y algunas de ellas tienen suministros de alimentos mientras que otras no.

Durante su viaje, debe comer suficiente comida para no pasar hambre. Hay (M) carreteras en el mapa, cada una conectando dos ciudades. Estos caminos son bidireccionales. Para cada camino, conocemos el costo exacto de los alimentos. Tenga en cuenta que solo cuando BaoBao llega a una ciudad que puede proporcionar alimentos, puede volver a llenar su comida al máximo de su capacidad.

BaoBao tiene planes de viaje (Q). Para cada plan, se garantiza que tanto la ciudad de inicio como la ciudad de destino tengan suministros de alimentos. Ahora BaoBao quiere que lo ayudes a determinar la capacidad máxima de comida de su carruaje para cada plan. Para su conveniencia, espera que sea lo más pequeño posible.

Entrada
Solo hay un caso de prueba.

La primera línea de la entrada contiene dos números enteros (N) y (M) ((1 \ le N \ le 10 ^ 5), (1 \ le M \ le 2 \ times 10 ^ 5)), lo que indica que hay ( N) ciudades y (M) carreteras bidireccionales.

La segunda línea contiene (N) números enteros (a_1, a_2, \ dots, a_N). Si (a_i = 1), la (i) -ésima ciudad tiene suministros de alimentos; Si (a_i = 0), la (i) -ésima ciudad no tiene suministros de alimentos.

Las siguientes (M) líneas contienen cada una tres números enteros (X), (Y) y (W) ((X \ ne Y), (1 \ le W \ le 10 ^ 9)), lo que indica que hay una carretera que conecta el (X) -th y la (Y) -th ciudad con un costo de comida de (W). Se garantiza que existe como máximo una carretera entre cada par de (X) e (Y).

La siguiente línea contiene un entero (Q) ((1 \ le Q \ le 10 ^ 5)), el número de consultas.

Las siguientes líneas (Q) contienen cada una dos números enteros (X) e (Y), que denotan la ciudad de inicio y la ciudad de destino para cada consulta. Está garantizado que tanto (X) como (Y) son ciudades con suministros de alimentos.

Salida
Para cada salida de consulta, una línea que contiene un número entero, que indica la capacidad de comida más pequeña.

Entrada de muestra
6 7
1 0 1 0 1 1
1 2 2
1 4 1
2 3 2
4 5 4
3 6 10
3 5 2
5 6 5
2
1 6
1 5
Salida de muestra
5
4

Pregunta: En
un gráfico no dirigido, algunos puntos pueden estar llenos de energía (convertirse en el valor de energía inicial) y la energía no se puede reducir a un número negativo al caminar. Se dan dos puntos para cada consulta, y encuentre la energía mínima que puede quedar del punto A al punto B (debe determinar la energía inicial).
Asegúrese de que los puntos que solicita sean todos puntos que se puedan cargar

Idea:
Después de leer la solución, me di cuenta de que MST también puede mantener el lado más grande (pequeño) de la ruta entre dos puntos, porque la conexión mantenida por el árbol de expansión mínimo cada vez es el lado más corto de los dos componentes conectados. (Se olvida la teoría de grafos.

Definición d [x] d [x]d [ x ] es la distancia desde x hasta la pila de carga más cercana, y luego reemplaza el lado (x, y, w) con (x, y, w + d [x] + d [y]), que representa el costo mínimo de este lado . En este momento, el problema es encontrar el borde mínimo de la ruta de dos puntos, por lo que el árbol de expansión mínimo se utiliza para el mantenimiento.

Dado que se supone que la energía inicial es V, entonces la energía para alcanzar el punto de inicio y el punto final es toda V, por lo que, en esencia, queremos minimizar V. Después de que este punto llega a cualquier punto, necesitamos realizar algunas operaciones para hacer que la energía actual de este punto sea lo más grande posible, de modo que la energía inicial requerida V sea lo más pequeña posible.

Entonces, para el borde x-> y, el peso del borde w. Primero caminamos desde x hasta la pila de carga más cercana y luego regresamos. En este momento, la energía es la mayor en el punto x, VVV es al menosd [x] d [x]d [ x ] . Después de pasar este borde al punto B, V es al menosd [x] + wd [x] + wd [ x ]+w . En este momento se alcanza el punto B, pero todavía tenemos que comenzar desde el punto B, por lo que tenemos que maximizar la energía del punto B y no podemos garantizar que la energía sea negativa, por lo que en este momento V es al menosd [x] + d [y] + wd [x ] + d [y] + wd [ x ]+d [ y ]+w , este es el límite de esta arista a la energía inicial V.

Encuentre el valor máximo del límite de ruta de dos puntos, que es la energía inicial mínima.

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>

using namespace std;

typedef long long ll;
const int maxn = 4e5 + 7;

int head[maxn],nex[maxn],to[maxn],tot;
ll val[maxn];
int vis[maxn];
ll d[maxn];
int a[maxn];
priority_queue<pair<ll,int>>q;

void add(int x,int y,ll z) {
    
    
    to[++tot] = y;
    nex[tot] = head[x];
    val[tot] = z;
    head[x] = tot;
}

void dijkstra() {
    
    
    while(!q.empty()) {
    
    
        int now = q.top().second;q.pop();
        if(vis[now]) continue;
        vis[now] = 1;
        for(int i = head[now];i;i = nex[i]) {
    
    
            int v = to[i];
            ll w = val[i];
            if(d[v] > d[now] + w) {
    
    
                d[v] = d[now] + w;
                q.push({
    
    -d[v],v});
            }
        }
    }
}

struct Edge {
    
    
    int x,y;
    ll w;
}edges[maxn];

int cmp(Edge a,Edge b) {
    
    
    return a.w < b.w;
}

int fa[maxn][20];
ll fw[maxn][20];
int f[maxn];

void dfs(int x) {
    
    
    for(int i = head[x];i;i = nex[i]) {
    
    
        int v = to[i];
        ll w = val[i];
        if(!d[v]) {
    
    
            d[v] = d[x] + 1;
            fa[v][0] = x;
            fw[v][0] = w;
            dfs(v);
        }
    }
}

int findset(int x) {
    
    
    if(f[x] == x) return x;
    return f[x] = findset(f[x]);
}

ll lca(int x,int y) {
    
    
    ll ans = 0;
    if(d[x] < d[y]) {
    
     //保证x是最深的
        swap(x,y);
    }
    
    for(int i = 19;i >= 0;i--) {
    
     //x跳到和y一样高
        if(d[fa[x][i]] >= d[y]) {
    
    
            ans = max(ans,fw[x][i]);
            x = fa[x][i];
        }
    }

    if(x == y) {
    
    
        return ans;
    }
    for(int i = 19;i >= 0;i--) {
    
     //两个小朋友一起跳
        if(fa[x][i] != fa[y][i]) {
    
    
            ans = max(fw[x][i],ans);
            ans = max(fw[y][i],ans);
            x = fa[x][i];
            y = fa[y][i];
        }
    }
    ans = max(ans,max(fw[x][0],fw[y][0]));
    return ans;
}

int main() {
    
    
    int n,m;scanf("%d%d",&n,&m);
    memset(d,0x3f,sizeof(d));
    for(int i = 1;i <= n;i++) {
    
    
        scanf("%d",&a[i]);
        if(a[i]) {
    
    
            q.push({
    
    0,i});
            d[i] = 0;
        }
    }
    for(int i = 1;i <= m;i++) {
    
    
        int x,y,w;scanf("%d%d%d",&x,&y,&w);
        edges[i] = {
    
    x,y,w};
        add(x,y,w);
        add(y,x,w);
    }
    
    dijkstra();
    for(int i = 1;i <= m;i++) {
    
    
        edges[i].w += d[edges[i].x] + d[edges[i].y];
    }
    sort(edges + 1,edges + 1 + m,cmp);

    tot = 0;
    memset(d,0,sizeof(d));
    memset(head,0,sizeof(head));
    
    for(int i = 1;i <= n;i++) f[i] = i;
    for(int i = 1;i <= m;i++) {
    
    
        int x = edges[i].x,y = edges[i].y;
        ll w = edges[i].w;
        int rx = findset(x),ry = findset(y);
        if(rx != ry) {
    
    
            f[rx] = ry;
            add(x,y,w);
            add(y,x,w);
        }
    }
    
    fa[1][0] = 0;
    d[1] = 1;
    dfs(1);
    for(int i = 1;i <= n;i++) {
    
    
        if(!d[i]) dfs(i);
    }
    
    for(int i = 1;i <= 19;i++) {
    
    
        for(int j = 1;j <= n;j++) {
    
    
            fa[j][i] = fa[fa[j][i - 1]][i - 1];
            fw[j][i] = max(fw[fa[j][i - 1]][i - 1],fw[j][i - 1]);
        }
    }
    
    int T;scanf("%d",&T);
    while(T--) {
    
    
        int x,y;scanf("%d%d",&x,&y);
        printf("%lld\n",lca(x,y));
    }
    return 0;
}

Supongo que te gusta

Origin blog.csdn.net/tomjobs/article/details/109072969
Recomendado
Clasificación