ACM-ICPC 2018 徐州赛区网络预赛 J-Maze Designer

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/ACMER_2333/article/details/82633765

Maze Designer

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×MN \times MN×M little squares. That is to say, the height of the rectangle is NNN and the width of the rectangle is MMM. 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 QQQ 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 NNN and MMM (1≤N,M≤5001 \le N,M \le 5001≤N,M≤500), giving the number of rows and columns of the maze.

The next N×MN \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,1) , (1,2)(1,2)(1,2) ⋯\cdots⋯ (1,M)(1,M)(1,M) , (2,1)(2,1)(2,1) , (2,2)(2,2)(2,2) , ⋯\cdots⋯ , (2,M)(2,M)(2,M) , ⋯\cdots⋯ ,(N,M)(N,M)(N,M).

Each line contains two characters DDD and RRR and two integers aaa , bbb (0≤a,b≤20000000000 \le a,b \le 20000000000≤a,b≤2000000000 ), aaa is the cost of building the wall between it and its lower adjacent square, and bbb 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 000.

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

The next QQQ lines gives four integers, x1x_1x1​, y1y_1y1​, x2x_2x2​, y2y_2y2​ ( 1≤x11 \le x_11≤x1​ , x2≤Nx_2 \le Nx2​≤N , 1≤y11 \le y_11≤y1​ , y2≤My_2 \le My2​≤M ), which represent two squares and their coordinate are (x1x_1x1​ , y1y_1y1​) and (x2x_2x2​ , y2y_2y2​).

(xxx,yyy) means row xxx and column yyy.

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 徐州赛区网络预赛

题目大意:从建好的墙中去除一些墙,使得剩余的墙的修建费用最小,的给出Q个询问,问拆除过墙后两点之间的距离(两个相邻的节点的距离为1)。

分析:为了使剩余的墙的修建价值最小,所以要拆的墙是一棵最大生成树才可以使得剩余墙的修建价值最大,然后在这棵最大生成树上跑个LCA就行了。

代码:

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll maxn=550*550;
ll n,m;
ll idex=0;
ll pre[maxn];
bool vis[maxn];
ll qhead[maxn];
ll head[maxn];
ll lca[maxn];
ll dis[maxn];
struct node
{
    ll from;
    ll next;
    ll to;
    ll id;
    ll val;
};
struct EDGE
{
    ll from;
    ll to;
    ll val;
} Q[maxn*2+10];
node edge[maxn*2];
node qedge[maxn*2];
ll cnt=0;
void add(ll from,ll to,ll idex)
{
    qedge[cnt].id=idex;
    qedge[cnt].from=from;
    qedge[cnt].next=qhead[from];
    qedge[cnt].to=to;
    qhead[from]=cnt;
    cnt++;
}
void add1(ll from,ll to)
{
    edge[++cnt].to=to;
    edge[cnt].from=from;
    edge[cnt].next=head[from];
    edge[cnt].val=1;
    head[from]=cnt;
}
bool cmp(EDGE a,EDGE b)
{
    return a.val>b.val;
}
ll Find(ll x)
{
    if(pre[x]!=x)
        pre[x]=Find(pre[x]);
    return pre[x];
}
void Create_tree()
{
    sort(Q+1,Q+1+idex,cmp);
    for(ll i=1; i<=n*m; i++) pre[i]=i;
    for(ll i=1; i<=idex; i++)
    {
        ll x=Find(Q[i].from);
        ll y=Find(Q[i].to);
        if(x!=y)
        {
            add1(Q[i].from,Q[i].to);
            add1(Q[i].to,Q[i].from);
            pre[x]=y;
        }
    }
}
void dfs(ll x)
{
    vis[x]=true;       ///标记访问过的节点
    for(ll i=head[x]; i!=-1; i=edge[i].next)
    {
        if(!vis[edge[i].to])
        {
            dis[edge[i].to]=dis[x]+edge[i].val;    ///edge[i].to距离根节点之间的距离
            dfs(edge[i].to);                       ///继续搜索该节点的子节点
            pre[edge[i].to]=x;                     ///用来标记父节点
        }
    }
    for(ll i=qhead[x]; i!=-1; i=qedge[i].next)
    {
        if(vis[qedge[i].to])                        ///该节点已经访问过了
        {
            lca[qedge[i].id]=Find(qedge[i].to);     ///用来标记所查询的两节点的公共最近节点的标号
            lca[qedge[i^1].id]=lca[qedge[i].id];
        }
    }
}
void init()
{
    memset(qhead,-1,sizeof(qhead));
    memset(head,-1,sizeof(head));
    memset(lca,-1,sizeof(lca));
}
void CIN()
{
    ll idex1=1;
    for(ll i=1; i<=n*m; i++)
    {
        for(ll j=1; j<=2; j++)
        {
            ll val;
            char str;
            scanf(" %c %lld",&str,&val);
            if(str=='X')
                continue;
            else if(str=='D')
            {
                Q[++idex].from=idex1;
                Q[idex].to=idex1+n;
                Q[idex].val=val;
            }
            else
            {
                Q[++idex].from=idex1;
                Q[idex].to=idex1+1;
                Q[idex].val=val;
            }
        }
        idex1++;
    }
}
int main()
{
    while(~scanf("%lld%lld",&n,&m))
    {
        idex=0;
        cnt=0;
        init();
        CIN();  ///读入
        Create_tree();   ///找最大生成树(Kruskal)
        cnt=0;
        ll q;
        scanf("%lld",&q);
        for(ll i=1; i<=q; i++)       ///我这里离散化查询了
        {
            ll x1,y1,x2,y2;
            scanf("%lld%lld%lld%lld",&x1,&y1,&x2,&y2);
            ll from=(x1-1)*m+y1;
            ll to=(x2-1)*m+y2;
            add(from,to,i);         ///记录查询点
            add(to,from,i);
        }
        for(ll i=1; i<=n*m; i++)
            pre[i]=i;
        memset(dis,0,sizeof(dis));
        memset(vis,false,sizeof(vis));
        dfs(1);                         ///LCA
        for(ll i=0; i<2*q; i+=2)
        {
            printf("%lld\n",dis[qedge[i].from]+dis[qedge[i].to]-2*dis[lca[qedge[i].id]]);
        }
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/ACMER_2333/article/details/82633765