并查集·UVA 1665·Islands

题目大意:

给定n*m的矩阵,格子中的数均<1e9;

在给定t个数,求格子中≥ti的数所组成的四连通块有几个。

解题思路:

这题使用了并查集求联通块,这个题目如果从图中一个一个找出肯定超时,但是如果根据一个格子的上下左右增添联通块,那会简单的多(至少不用遍历这张图了),具体做法:

我们给格子中的每个数按照权值大小排好顺序,并且从大到小取ti,因为这样,再将大于某一值res的联通块已经将所有格子都用过,那么我们并不需要再往下找了,整个图就是一个联通块,直接将剩下的赋值为1就好了。

剩下要做的就是从大到小的取出格子中的数,依次增添联通块。

网上有个代码中有这样一种操作;

!~p,,,,,,,,,,,,这TM不就是 p == -1 嘛,有毒吧,,在时间上能节约很大嘛???

AC代码:

#include <map>
#include <set>
#include <stack>
#include <cmath>
#include <queue>
#include <bitset>
#include <string>
#include <vector>
#include <cstdio>
#include <cctype>
#include <fstream>
#include <cstdlib>
#include <sstream>
#include <cstring>
#include <iostream>
#include <algorithm>
#pragma comment(linker, "/STACK:1024000000,1024000000")

using namespace std;
#define   maxn          100000 + 7
#define   lson          l,m,rt<<1
#define   rson          m+1,r,rt<<1|1
#define   ms(x,y)      memset(x,y,sizeof(x))
#define   rep(i,n)      for(int i=0;i<(n);i++)
#define   repf(i,a,b)   for(int i=(a);i<=(b);i++)
#define   pii           pair<int,int>
//#define   mp            make_pair
#define   FI            first
#define   SE            second
#define   IT            iterator
#define   PB            push_back
#define   Times         10
typedef   long long     ll;
typedef   unsigned long long ull;
typedef   long double   ld;

const double eps = 1e-10;
const double  pi = acos(-1.0);
const  ll    mod = 1e9+7;
const  int   inf = 0x3f3f3f3f;
const  ll    INF = (ll)1e18+300;
int mapp[1010][1010];
int n, m;
int fa[1010*1010];
int tt[maxn];
int dire[4][2] = {{0,1},{0,-1},{1,0},{-1,0}};

struct Node{
    int x, y;
    int val;
}node[1010*1010];
int find(int x){
    if(fa[x] != x) {
        fa[x] = find(fa[x]);
    }
    return fa[x];
}

bool cmp(Node a, Node b) {
    return a.val < b.val;
}

bool judge(int x,int y, int c) {
    if(x >= 0 && x < n && y >= 0 && y < m && mapp[x][y] > c) {
        return true;
    }
    return false;
}

int main() {
    int t;
    cin >> t;
    while(t -- ) {
        ms(fa, -1);
        cin >> n >> m;
        int pos = 0;
        for (int i = 0; i < n; i++){
            for (int j = 0 ; j < m; j ++) {
                cin >> mapp[i][j];
                //pos = i * m + j;
                node[pos].x = i;
                node[pos].y = j;
                node[pos++].val = mapp[i][j];
            }
        }
        sort(node, node+n*m, cmp);

        int t;
        cin >> t;
        for (int i = 0; i < t; i++) {
            cin >> tt[i];
        }
        int len = n*m - 1;
        int ans = 0;
        for (int i = t-1; i >= 0; i--) {
            if(tt[i] < node[len].val) {
                while(len >= 0 && tt[i] < node[len].val) {
                    int pos = node[len].x * m + node[len].y;
                    if(fa[pos] == -1) {
                        fa[pos] = pos;
                        ans ++;
                    }
                    for (int j = 0; j < 4; j++){
                        int dx = node[len].x + dire[j][0];
                        int dy = node[len].y + dire[j][1];
                        if(judge(dx, dy, tt[i])) {
                            int pos1 = dx * m + dy;
                            if(fa[pos1] != -1) {
                                int u = find(pos);
                                int v = find(pos1);
                                if(u != v) {
                                    fa[u] = v;
                                    ans --;
                                }
                            }
                        }
                    }
                    len --;
                }
                if(len < 0 ) {
                    while(1) {
                        if(i < 0) {
                            break;
                        }
                        tt[i--] = 1;
                    }
                    break;
                }
            }
            tt[i] = ans;
        }
        for (int i = 0 ;i < t; i++) {
            cout << tt[i] << " ";
        }
        cout << endl;
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值