[USACO14JAN]滑雪等级Ski Course Rating

题目描述

The cross-country skiing course at the winter Moolympics is described by an M x N grid of elevations (1 <= M,N <= 500), each elevation being in the range 0 .. 1,000,000,000.

Some of the cells in this grid are designated as starting points for the course. The organizers of the Moolympics want to assign a difficulty rating to each starting point. The difficulty level of a starting point P should be the minimum possible value of D such that a cow can successfully reach at least T total cells of the grid (1 <= T <= MN), if she starts at P and can only move from cell to adjacent cell if the absolute difference in elevation between the cells is at most D. Two cells are adjacent if one is directly north, south, east, or west of the other.

Please help the organizers compute the difficulty rating for each starting point.

滑雪场用一个M*N(1 <= M,N <= 500)的数字矩阵表示海拔高度,每个数字表示一个范围在0 .. 1,000,000,000的高度。有些格子被指定为起点,组织者想对这些起点做难度评级。

如果起点P点是一个难度级别为D的起点,则D必须是满足以下条件的一个最小值:

(1)从一个格子只能滑到相邻的格子;

(2)这两个格子的海拔差不超过D;

(3)至少能够到达T(1 <= T <= M*N)个格子(包括起点本身)。

输入输出格式

输入格式:

* Line 1: The integers M, N, and T.

* Lines 2..1+M: Each of these M lines contains N integer elevations.

* Lines 2+M..1+2M: Each of these M lines contains N values that are either 0 or 1, with 1 indicating a cell that is a starting point.

输出格式:

* Line 1: The sum of difficulty ratings of all starting points (note that this may not fit into a 32-bit integer, even though individual difficulty ratings will).

输入输出样例

输入样例#1: 
3 5 10 
20 21 18 99 5 
19 22 20 16 17 
18 17 40 60 80 
1 0 0 0 0 
0 0 0 0 0 
0 0 0 0 1 
输出样例#1: 
24 

说明

The ski course is described by a 3 x 5 grid of elevations. The upper-left and lower-right cells are designated as starting points. From each starting point, we must be able to reach at least 10 cells.

The difficulty rating of the upper-left starting point is 4, and for the lower-right it is 20.


 

woc我要骂人, 这sb题调了我2小时。

日了,不知道哪里的玄学错误找错找了2小时, 最后重写了一边才A。

吐槽完了ri....

一看这道题...水...暴力二分+bfs结果光荣tle;

 

emm...

我们把每个点与它下边和右边的点连起来,边权是他们的高度差,然后按照边权排序,不停的合并两个端点的集合。

一旦发现两个集合合并之后,它的siz>T,那么立即更新答案,但是以前更新过的集合不需要加入打哪中。

然后再按秩合并。

我们维护每一个集合的siz, num(是这个集合里有多少个出发点);

然后更新答案的时候, 如果之前的那个小集合没有更新过答案,那么ans += ed[i].val * num[x];

因为我们边权是从小到达排序的,所以不用担心得到错误的答案,使得这个集合大小第一次大于T的边,一定是满足题意的最小边。


 

附上折磨了我一晚上的代码...

 

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std;
inline int read(){
    int res=0;char ch=getchar();bool fl=0;
    while(!isdigit(ch)){if(ch=='-')fl=1;ch=getchar();}
    while(isdigit(ch)){res=(res<<3)+(res<<1)+(ch^48);ch=getchar();}
    return fl?-res:res;
}
int dx[]={0, 1, 0}, dy[]={0, 0, 1};
int n, m, T;
int cnt, tot;
long long ans;
struct edge{
    int x, y, val;
    bool operator < (edge b) {return val < b.val;}
}ed[250005];
int h[505][505];
int fa[250005], sz[250005];
int id[505][505], num[250005];
int Find(int x){return x==fa[x]?x:fa[x]=Find(fa[x]);}

signed main()
{
    n = read(), m = read(), T = read();
    tot = 0;
    for (register int i = 1 ; i <= n ; i ++)
    {
        for (register int j = 1 ; j <= m ; j ++)
        {
            h[i][j] = read();
            tot+=1;
            id[i][j] = tot;
            fa[id[i][j]] = id[i][j];
            sz[id[i][j]] = 1;
        }
    }
    //cout<<tot<<endl;
    for (int i = 1; i <= n; ++i)
    {
        for (int j = 1; j <= m; ++j)
        {
            int o = read();
            if (o) num[id[i][j]]=1;
            for (int k = 1; k <= 2; ++ k)
            {
                int tx=i+dx[k],ty=j+dy[k];
                if (tx<n+1&&ty<m+1) ed[++cnt]=(edge){id[i][j],id[tx][ty],abs(h[i][j]-h[tx][ty])};
            }
        }
    }
//    cout<<tot<<endl;
//    cout<<n<<endl<<m<<endl;
//    cout<<n*m<<endl;
    sort(ed + 1, ed + 1 + cnt);
//    cout<<cnt<<endl;
    for (register int i = 1 ; i <= cnt ; i ++)
    {
        int x = ed[i].x, y = ed[i].y;
        int fx = Find(x), fy = Find(y);
        if (fx== fy) continue;
        if (sz[fx] + sz[fy] >= T)
        {
            if (sz[fx] < T) ans += 1ll * ed[i].val * num[fx];
            if (sz[fy] < T) ans += 1ll * ed[i].val * num[fy];
        }
        if (sz[fx] > sz[fy]) swap(fx, fy);
        fa[fx] = fy;
        sz[fy] += sz[fx], num[fy] += num[fx];
    }
    cout<<ans<<endl;
    return 0;
}

 

 

 

posted @ 2018-07-20 22:53  zZhBr  阅读(384)  评论(0编辑  收藏  举报