J. Maze Designer(ACM-ICPC 2018 徐州賽區網絡預賽,最大生成樹,LCA)

描述

After the long vacation, the maze designer master has to do his job. A tour company gives him a map which is a rectangle. The map consists of N \times MN×M little squares. That is to say, the height of the rectangle is NN and the width of the rectangle is MM. The master knows exactly how the maze is going to use. The tour company will put a couple in two different squares in the maze and make them seek each other. Of course,the master will not make them find each other easily. The only thing the master does is building some wall between some little squares. He knows in that way, wherever the couple is put, there is only one path between them. It is not a difficult thing for him, but he is a considerate man. He also knows that the cost of building every wall between two adjacent squares is different(Nobody knows the reason). As a result, he designs the maze to make the tour company spend the least money to build it.

Now, here’s your part. The tour company knows you’re the apprentice of the master, so they give you a task. you’re given QQ qustions which contain the information of where the couple will be put. You need to figure out the length of the shortest path between them.

However,the master doesn’t tell you how he designs the maze, but he believes that you, the best student of himself, know the way. So he goes on vacation again.

Input

The first line of the input contains two integers NN and MM (1 \le N,M \le 5001≤N,M≤500), giving the number of rows and columns of the maze.

The next N \times MN×M lines of the input give the information of every little square in the maze, and their coordinates are in order of (1,1)(1,1) , (1,2)(1,2) \cdots⋯ (1,M)(1,M) , (2,1)(2,1) , (2,2)(2,2) , \cdots⋯ , (2,M)(2,M) , \cdots⋯ ,(N,M)(N,M).

Each line contains two characters DD and RR and two integers aa , bb (0 \le a,b \le 20000000000≤a,b≤2000000000 ), aa is the cost of building the wall between it and its lower adjacent square, and bb is the cost of building the wall between it and its right adjacent square. If the side is boundary, the lacking path will be replaced with X 00.

The next line contains an integer QQ (1 \le Q \le 1000001≤Q≤100000 ), which represents the number of questions.

The next QQ lines gives four integers, x_1x1, y_1y1, x_2x2, y_2y2 ( 1 \le x_11≤x1 , x_2 \le Nx2≤N , 1 \le y_11≤y1 , y_2 \le My2≤M ), which represent two squares and their coordinate are (x_1x1 , y_1y1) and (x_2x2 , y_2y2).

(xx,yy) means row xx and column yy.

It is guaranteed that there is only one kind of maze.

Output

For each question, output one line with one integer which represents the length of the shortest path between two given squares.

樣例輸入

3 3
D 1 R 9
D 7 R 8
D 4 X 0
D 2 R 6
D 12 R 5
D 3 X 0
X 0 R 10
X 0 R 11
X 0 X 0
3
1 1 3 3
1 2 3 2
2 2 3 1

樣例輸出

4
2
2

題目來源

ACM-ICPC 2018 徐州賽區網絡預賽

思路

先說題意,你需要設計一個矩形的迷宮,這個迷宮是n×m 的,這個迷宮是給情侶設計的,旅遊公司會把這對情侶放在迷宮的某兩個位置,讓他們相互尋找,現在要在迷宮中建造一些牆壁,使得這對情侶之間只有一條路,讓他們能夠相互找到,在迷宮的兩個相鄰的格子建造牆壁會有不同花費。旅遊公司想花費最少的錢來建造這個迷宮,然後有q個詢問,詢問你在建立若干堵牆後,使得任意兩點間的路徑都唯一且花費最少的情況下,兩個點之間的距離。

樣例給出是首先給出nm ,然後給出nm 行,每行的D x代表花費x元可以向下建造一個牆壁,R x代表向右建造牆壁的花費,X 0這樣代表不能建造。

因爲題目要保證只有一條路徑可以到達,那麼這肯定是一棵樹,任意兩點路徑唯一且花費最少,也就是需要求一下最大生成樹,最後求兩點之間距離時,求lca即可。

如樣例,建圖後爲:

最大生成樹爲:

首先建圖跑一下最大生成樹,在最大生成樹上跑lca,我的代碼是通過樹鏈剖分實現的,求出最近公共祖先後,兩個點和他們的lca的差的絕對值之和就是答案。

代碼

#include <bits/stdc++.h>
using namespace std;
#define mem(a, b) memset(a, b, sizeof(a))
typedef long long ll;
const ll N = 1e6 + 10;
ll tot1, n, m;
ll fa[N], dep[N], siz[N], son[N], top[N];
ll first[N], tot, cnt;
ll pre[N];
struct edge
{
    ll v, next;
} e[N * 2];
void init()
{
    mem(first, -1);
    tot = 0;
    cnt = 0;
    tot1 = 0;
    for (ll i = 1; i <= n * m; i++)
        pre[i] = i;
}
void add_edge(ll u, ll v)
{
    e[tot].v = v;
    e[tot].next = first[u];
    first[u] = tot++;
}
void dfs1(ll u, ll f, ll deep)
{
    fa[u] = f;
    dep[u] = deep;
    siz[u] = 1;
    son[u] = 0;
    ll maxson = -1;
    for (ll i = first[u]; ~i; i = e[i].next)
    {
        ll v = e[i].v;
        if (v == f)
            continue;
        dfs1(v, u, deep + 1);
        siz[u] += siz[v];
        if (siz[v] > maxson)
        {
            son[u] = v;
            maxson = siz[v];
        }
    }
}
void dfs2(ll u, ll topf)
{
    top[u] = topf;
    if (!son[u])
        return;
    dfs2(son[u], topf);
    for (ll i = first[u]; ~i; i = e[i].next)
    {
        ll v = e[i].v;
        if (v == fa[u] || v == son[u])
            continue;
        dfs2(v, v);
    }
}
ll qlca(ll x, ll y)
{
    while (top[x] != top[y])
    {
        if (dep[top[x]] < dep[top[y]])
            swap(x, y);
        x = fa[top[x]];
    }
    return dep[x] < dep[y] ? x : y;
}
struct kedge
{
    ll u, v, w;
} ke[N];
ll find(ll x)
{
    return x == pre[x] ? x : pre[x] = find(pre[x]);
}
ll mix(ll x, ll y)
{
    ll fx = find(x), fy = find(y);
    if (fx != fy)
    {
        pre[fy] = fx;
        return 1;
    }
    return 0;
}
bool cmp(kedge a, kedge b)
{
    return a.w > b.w;
}
ll kruskal()
{
    sort(ke + 1, ke + tot1 + 1, cmp);
    ll sum = 0, num = 0;
    for (ll i = 1; i <= tot1; i++)
    {
        if (mix(ke[i].u, ke[i].v))
        {
            add_edge(ke[i].u, ke[i].v);
            add_edge(ke[i].v, ke[i].u);
            num++;
            sum += ke[i].w;
        }
        if (num == n * m - 1)
            break;
    }
    return sum;
}
ll abs(ll x, ll y)
{
    if (x > y)
        return x - y;
    return y - x;
}
int main()
{
    // freopen("in.txt", "r", stdin);
    char d[2], r[2];
    ll a, b;
    scanf("%lld%lld", &n, &m);
    init();
    for (ll i = 1; i <= n * m; i++)
    {
        scanf("%s%lld%s%lld", d, &a, r, &b);
        if (d[0] != 'X')
        {
            ke[++tot1].u = i;
            ke[tot1].v = i + n;
            ke[tot1].w = a;
        }
        if (r[0] != 'X')
        {
            ke[++tot1].u = i;
            ke[tot1].v = i + 1;
            ke[tot1].w = b;
        }
    }
    kruskal();
    dfs1(1, 0, 1);
    dfs2(1, 1);
    ll q;
    scanf("%lld", &q);
    while (q--)
    {
        ll x1, y1, x2, y2;
        scanf("%lld%lld%lld%lld", &x1, &y1, &x2, &y2);
        ll x = (x1 - 1) * m + y1, y = (x2 - 1) * m + y2;
        ll lca = qlca(x, y);
        printf("%lld\n", abs(dep[lca], dep[x]) + abs(dep[lca], dep[y]));
    }
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章