您的位置:首页 > 其它

DoIt is Being Flooded

2015-11-16 19:46 369 查看
Description

Global warming affects the whole world right now. DoIt is a country which is surrounded by the sea and suffering from global warming. Scientists in DoIt find out that the sea level will rise 1 meter every year so that some places in DoIt will be flooded
and disappear from the earth. As a result, the country may be divided into several islands and finally disappear.

DoIt's government wants to know how much it can earn before the whole country's disappearance. Thanks for economists, its income can be decided by the size of unflooded places and an economic coefficientA.
A will change with years and it has been well forecasted by economists. The total income of DoIt is the sum of all islands' income. For each island, its income equals2 Bits(S & A).
S is the size of the island and A is the economic coefficient of that year.Bits(x) means the number of 1 in
x's binary code.

Assuming DoIt can be represented by n * m grids, an integer in a grid indicates its altitude. The size of a grid is 1. Two grids are adjacent if they have a common edge. Note that, water in a grid can only flow into grids which are adjacent
to the current grid. At first, it's year 0 and the sea level is 0. Therefore, in thed-th year, the sea level will rise to
d at the very begining of the year. There are several queries asked by the government. Each query includes two integers,d,
A, representing the year and the economic coefficient of that year. You should output DoIt's total income in thed-th year. You can assume that the sea level changes at the beginning of the year and keeps unchanged in that year. So the total
income is caclulated after this change.

Input

There are multiple test cases (about 10).

For each case, in the first line there are two integers n and m (1 ≤n,
m ≤ 500). Then in the next n lines, each line has m integers. It's guaranteed that all altitudes are larger than 0 and no more than 1000000.

After that, there is an integer Q (1 ≤ Q ≤ 10000), representing the number of queries. In the nextQ lines, each line has two integers,
d (1 ≤ d ≤ 1000000) andA (0 ≤ A ≤ 1000000000). It's possible that different economic coefficients are found in the same year.

Output

For each query, output the total income of DoIt in that year.

Sample Input

5 5
6 6 6 6 8
5 2 2 2 5
5 2 3 2 4
8 2 1 1 5
7 4 5 5 5
4
3 255
5 255
7 255
9 255


Sample Output

8
6
4
0

Hint

Because of the large input, scanf is recommended.

题意:

一个图,每个点为一个建筑物,在发生洪水的时候有多少建筑是没有被淹的,

注意一点就是洪水只能从相邻的位置流进去,样例当高度为3时,是淹不到

建筑物的,最后的结果就是2^(每个连通块的个数&A的二进制位的个数),

统计和就是答案。

这道题涉及的东西挺多的,需要用优先队列将相邻的值设置成较大(开始只保存边界就行),

只能从边界流进去,所以每次出最小的值能流到的位置然后设置较大的那个值,然后

保存所有的值,这样就可以通过从大到小统计连通块,并统计每个连通块的个数,先

将答案预处理,然后只需要输出就行,保存答案时用数组就行,开始用map内存超限。

#include <stdio.h>
#include <queue>
#include <map>
#include <algorithm>
#include <string.h>
using namespace std;
#define CLR( a ) memset ( a, 0, sizeof ( a ) )
#define LL long long
#define DBUG printf ( "Here!\n" )
const int maxn = 505, M = maxn*maxn, QY = 10005;
const int dx[4] = { 0, 1, -1, 0 }, dy[4] = { 1, 0, 0, -1 };
int mp[maxn][maxn], n, m;
int father[M], num[M], ans[QY];
map < int, int > cur;
bool vis[maxn][maxn];
struct node
{
int h, x, y;
friend bool operator < ( node n1, node n2 )
{//优先队列小的先出,排序就是降序
return n1.h > n2.h;
}
} nd[M], t;
struct query
{
int d, a, i;
friend bool operator < ( query q1, query q2 )
{
return q1.d > q2.d;
}
}qry[QY];
priority_queue < node > q;
inline int Max ( int a, int b )
{
return a > b ? a : b;
}
inline bool check ( int x, int y )
{
return x < 0 || x >= n || y < 0 || y >= m;
}
void init ( )
{
for ( int i = 0; i <= n*m; i ++ )
{
father[i] = i;
num[i] = 1;
}
CLR ( vis );
cur.clear ( );
}
int find ( int x )
{
int r = x, i, j;
while ( r != father[r] )
r = father[r];
i = x;
while ( i != r )
{
j = father[i];
father[i] = r;
i = j;
}
return r;
}
void merge ( int fx, int fy )
{
father[fy] = fx;
num[fx] = num[fx]+num[fy];
}
int bit_cnt ( int n )
{
int ret = 0;
while ( n > 0 )
{
if ( n&1 )
ret ++;
n = n >> 1;
}
return ret;
}
int main ( )
{
int cnt, Q;
while ( ~ scanf ( "%d%d", &n, &m ) )
{
cnt = 0;
CLR ( vis );
while ( ! q.empty ( ) ) //清空
q.pop ( );
for ( int i = 0; i < n; i ++ )
for ( int j = 0; j < m; j ++ )
{
scanf ( "%d", &mp[i][j] );
if ( i == 0 || j == 0 || i == n-1 || j == m-1 )
{
nd[cnt].x = i, nd[cnt].y = j, nd[cnt].h = mp[i][j];
q.push ( nd[cnt] ); //将边界保存
cnt ++;
vis[i][j] = true;
}
}
while ( ! q.empty ( ) )
{
t = q.top ( );
q.pop ( );
for ( int i = 0; i < 4; i ++ )
{   //将最小值相邻设置成两个中比较大的那个
int nx = t.x+dx[i];
int ny = t.y+dy[i];
if ( check ( nx, ny ) || vis[nx][ny] )
continue ;
vis[nx][ny] = true; //标记
mp[nx][ny] = Max ( mp[nx][ny], mp[t.x][t.y] );
//设置成两个中间较大的值
nd[cnt].x = nx, nd[cnt].y = ny, nd[cnt].h = mp[nx][ny];
q.push ( nd[cnt] );
cnt ++;
}
}
sort ( nd, nd+cnt );    //降序
scanf ( "%d", &Q );
for ( int i = 0; i < Q; i ++ )
{
scanf ( "%d%d", &qry[i].d, &qry[i].a );
qry[i].i = i;   //注意将编号保存,输出的时候就可以直接输出
}
sort ( qry, qry+Q );
//对高度降序,那样就可以直接统计连通块块数和每块的个数
init ( );
for ( int i = 0, c = 0; i < Q; i ++ )
{
while ( c < cnt && nd[c].h > qry[i].d )
//统计所有高度大于d的个数,和连通块数
{
int x = nd[c].x, y = nd[c].y;
vis[x][y] = true;   //标记有此数
cur[1] ++;  //1个的个数加1
for ( int j = 0; j < 4; j ++ )  //判断连通的个数
{
int nx = x+dx[j];
int ny = y+dy[j];
if ( check ( nx, ny ) || vis[nx][ny] == false )
continue ;
int a = x*m+y, b = nx*m+ny;
//将二维换成一维的坐标
int fa = find ( a ), fb = find ( b );
if ( fa != fb )
{
cur[ num[fa] ] --;  //fa连通块的个数减1
if ( cur[ num[fa] ] == 0 )  //为0时删除
cur.erase ( num[fa] );
cur[ num[fb] ] --;  //fb同理
if ( cur[ num[fb] ] == 0 )
cur.erase ( num[fb] );
merge ( fa, fb );   //合并 将总个数求出
cur[ num[fa] ] ++;  //统计连通个数为num[fa]的个数
}
}
c ++;
}
int val = 0;
for ( map < int, int > :: iterator it = cur.begin ( ); it != cur.end ( ); it ++ )
val = val+( ( *it ).second << bit_cnt ( ( *it ).first & qry[i].a ) );
//迭代map,个数*( 1 << bit_cnt ( cnt & A ) )
ans[ qry[i].i ] = val;  //下标qry[i].i的值为val
}
for ( int i = 0; i < Q; i ++ )
printf ( "%d\n", ans[i] );
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: