zoukankan      html  css  js  c++  java
  • [USACO19OPEN]Valleys P && JZOJ 6525【2020.4.1模拟】Valleys (并查集+平面图欧拉公式):

    https://gmoj.net/senior/#main/show/6525

    若没有洞的限制,答案显然从每个点出发的极大联通块(联通块的每个点高度小于等于起点高度)的大小和。

    那么将高度排序,从小到大用并查集维护即可。

    现在要看有没有洞,考虑平面图欧拉公式:

    (V+F=E+2),其中(V)是点数,(F)是块数,(E)是边数,则(F=E+2-V)

    这里把每个格子定义为点,若相邻格子都属于当前并查集,则它们之间有边。

    不难发现(F=1(外面的大块)+相邻四个(小正方形)都属于当前并查集的个数+洞的个数)

    所以要动态地维护点数、边数、小正方形个数。

    若直接套用启发式合并,时间复杂度:(O(n^2~log~n^2*大常数)),卡一卡能过。

    仔细思考,发现每次是合并一个格子P和周围4个格子(高度小于(h[P]))。

    如果(P)周围的两个格子属于不同的并查集,那么它们的并查集的点之间是没有四相邻的,不然就已经被合并了。

    所以新产生的边和小正方形都包含(P),那么就暴力扫一扫(P)的周围就好了,时间复杂度(O(n^2~α))

    Code :


    #pragma GCC optimize(2)
    #include<bits/stdc++.h> 
    #define fo(i, x, y) for(int i = x, _b = y; i <= _b; i ++)
    #define ff(i, x, y) for(int i = x, _b = y; i <  _b; i ++)
    #define fd(i, x, y) for(int i = x, _b = y; i >= _b; i --)
    #define ll long long
    #define pp printf
    #define hh pp("
    ")
    using namespace std;
    
    const int N = 755;
    
    int n, a[N][N];
    
    #define pii pair<int, int>
    #define fs first
    #define se second
    
    pii b[N * N]; int b0;
    
    int cmpb(pii x, pii y) {
    	return a[x.fs][x.se] < a[y.fs][y.se];
    }
    
    int id[N][N];
    
    int mov[8][2] = {{1, 0}, {-1, 0}, {0, 1}, {0, -1}, {1, 1}, {1, -1}, {-1, 1}, {-1, -1}};
    
    int f[N * N], e[N * N], g[N * N], siz[N * N];
    
    int F(int x) { return f[x] == x ? x : (f[x] = F(f[x]));}
    
    void bin(int x, int y) {
    	if(F(x) != F(y)) {
    		x = f[x], y = f[y];
    		siz[y] += siz[x];
    		e[y] += e[x];
    		g[y] += g[x];
    		f[x] = f[y];
    	}
    }
    
    int qv(int x, int y, int w) { return F(id[x][y]) == w;}
    int calc_e(int x, int y, int w) {
    	int s = 0;
    	fo(j, 0, 3) s += qv(x + mov[j][0], y + mov[j][1], w);
    	return s;
    }
    int calc_g(int x, int y, int w) {
    	int s = 0;
    	s += qv(x - 1, y - 1, w) && qv(x - 1, y, w) && qv(x, y - 1, w);
    	s += qv(x - 1, y, w) && qv(x - 1, y + 1, w) && qv(x, y + 1, w);
    	s += qv(x, y + 1, w) && qv(x + 1, y, w) && qv(x + 1, y + 1, w);
    	s += qv(x, y - 1, w) && qv(x + 1, y - 1, w) && qv(x + 1, y, w);
    	return s;
    }
    
    int main() {
    	freopen("valleys.in", "r", stdin);
    	freopen("valleys.out", "w", stdout);
    	scanf("%d", &n);
    	fo(i, 1, n) fo(j, 1, n) {
    		scanf("%d", &a[i][j]);
    		b[++ b0] = pii(i, j);
    		id[i][j] = (i - 1) * n + j;
    	}
    	sort(b + 1, b + b0 + 1, cmpb);
    	fo(i, 1, n * n) f[i] = i, siz[i] = 1;
    	ll ans = 0;
    	fo(i, 1, b0) {
    		int x = b[i].fs, y = b[i].se;
    		fo(j, 0, 3) {
    			int u = x + mov[j][0], v = y + mov[j][1];
    			if(u && v && u <= n && v <= n) {
    				if(a[u][v] < a[x][y]) {
    					bin(id[u][v], id[x][y]);
    				}
    			}
    		}
    		int w = F(id[x][y]);
    		e[w] += calc_e(x, y, w);
    		g[w] += calc_g(x, y, w);
    		if(e[w] + 2 - siz[w] - g[w] == 1)
    			ans += siz[w];
    	}
    	pp("%lld
    ", ans);
    }
    
  • 相关阅读:
    day12 Python操作rabbitmq及pymsql
    day11 队列、线程、进程、协程及Python使用缓存(redis/memcache)
    day10 Python作用域 Python2.7与Python3.x的类继承的区别、异步IO、多进程,多线程简介
    day09 Python socket编程
    day08 面向对象补充及单例模式
    day07 configparser xml subprocess 面向对象
    day06 Python的一些内建变量、反射、hashlib模块、re模块、os模块、sys模块
    day05 Python多层装饰器、模块、序列化、字符串格式化、生成器和迭代器、递归、time、datetime模块、logging模块
    day04 Python一些内置函数及装饰器
    查看旧版jexus命令
  • 原文地址:https://www.cnblogs.com/coldchair/p/12618380.html
Copyright © 2011-2022 走看看