zoukankan      html  css  js  c++  java
  • 「BZOJ4242」水壶

    传送门
    Luogu团队题链接

    解题思路

    考虑以图中的建筑为点建一张图,那么我们就只要求出这个图的 ( ext{Kruskal}) 重构树然后按套路搞就行了。
    重点是优化连边,因为直接连边边数就会太多贼JB多
    考虑 ( ext{BFS}),我们把所有建筑都作为源点跑 ( ext{BFS}),求出每个点的距离他最近的建筑以及这段距离。
    然后只要两个相邻点的最近建筑不同,就把这两个最近建筑连边,边数就优化到了 (O(4 imes H imes W)) 级别(思想参照这题

    细节注意事项

    • 这题我调了一上午,原因有:
      太菜:并查集忘记合并。
      太菜:忘记倍增。
      太菜:忘记判 (-1)

    参考代码

    #include <algorithm>
    #include <iostream>
    #include <cstring>
    #include <cstdlib>
    #include <cstdio>
    #include <cctype>
    #include <cmath>
    #include <ctime>
    #include <queue>
    #define rg register
    using namespace std;
    template < typename T > inline void read(T& s) {
    	s = 0; int f = 0; char c = getchar();
    	while (!isdigit(c)) f |= c == '-', c = getchar();
    	while (isdigit(c)) s = s * 10 + (c ^ 48), c = getchar();
    	s = f ? -s : s;
    }
    
    typedef long long LL;
    const int _ = 2002;
    const int __ = 200002;
    const int dx[] = { 0, 0, 1, -1 };
    const int dy[] = { 1, -1, 0, 0 };
    
    queue < pair < int, int > > Q;
    
    int n, m, p, q, node;
    int a[_][_], id[_][_]; LL dis[_][_];
    int dep[__ * 2], fa[22][__ * 2]; LL val[__ * 2];
    
    struct Edge { int x, y; LL w; }edge[_ * _ * 2]; int cnt;
    inline bool cmp(const Edge& x, const Edge& y) { return x.w < y.w; }
    
    int Fa[__ * 2];
    inline int findd(int x) { return Fa[x] == x ? x : Fa[x] = findd(Fa[x]); }
    
    inline int get(int x) { return !x || dep[x] ? dep[x] : dep[x] = get(fa[0][x]) + 1; }
    
    inline void Kruskal() {
    	for (rg int i = 1; i <= p; ++i) Fa[i] = i;
    	sort(edge + 1, edge + cnt + 1, cmp);
    	node = p;
    	for (rg int i = 1; i <= cnt; ++i) {
    		int fx = findd(edge[i].x);
    		int fy = findd(edge[i].y);
    		if (fx == fy) continue;
    		++node;
    		Fa[node] = Fa[fx] = Fa[fy] = node;
    		fa[0][fx] = fa[0][fy] = node, val[node] = edge[i].w;
    	}
    	for (rg int i = 1; i <= node; ++i) get(i);
    	for (rg int i = 1; i <= 20; ++i)
    		for (rg int j = 1; j <= node; ++j)
    			fa[i][j] = fa[i - 1][fa[i - 1][j]];
    }
    
    inline LL LCA(int x, int y) {
    	if (findd(x) != findd(y)) return -1;
    	if (dep[x] < dep[y]) swap(x, y);
    	for (rg int i = 20; ~i; --i) if (dep[fa[i][x]] >= dep[y]) x = fa[i][x];
    	if (x == y) return x;
    	for (rg int i = 20; ~i; --i) if (fa[i][x] != fa[i][y]) x = fa[i][x], y = fa[i][y];
    	return val[fa[0][x]];
    }
    
    int main() {
    #ifndef ONLINE_JUDGE
     	freopen("in.in", "r", stdin);
    #endif
    	read(n), read(m), read(p), read(q); 
    	char s[_]; 
    	for (rg int i = 1; i <= n; ++i) {
    		scanf("%s", s + 1); 
    		for (rg int j = 1; j <= m; ++j) a[i][j] = s[j] == '.'; 
    	}
    	memset(dis, -1, sizeof dis); 
    	for (rg int x, y, i = 1; i <= p; ++i)
    		read(x), read(y), Q.push(make_pair(x, y)), id[x][y] = i, dis[x][y] = 0; 
    	while (!Q.empty()) {
    		pair < int, int > x = Q.front(); Q.pop(); 
    		int i = x.first, j = x.second; 
    		for (rg int ni, nj, k = 0; k < 4; ++k) {
    			ni = i + dx[k], nj = j + dy[k]; 
    			if (ni < 1 || ni > n || nj < 1 || nj > m) continue; 
    			if (!a[ni][nj]) continue; 
    			if (id[ni][nj]) {
    				if (id[i][j] != id[ni][nj])
    					edge[++cnt] = (Edge) { id[i][j], id[ni][nj], dis[i][j] + dis[ni][nj] };
    			} else
    				dis[ni][nj] = dis[i][j] + 1, id[ni][nj] = id[i][j], Q.push(make_pair(ni, nj)); 
    		}
    	}
    	Kruskal();
    	for (rg int x, y; q--; ) read(x), read(y), printf("%lld
    ", LCA(x, y)); 
    	return 0;
    }
    

    完结撒花 (qwq)

  • 相关阅读:
    机器学习--k-means聚类原理
    机器学习--朴素贝叶斯模型原理
    关联分析原理小结
    批发经销商客户价值细分
    员工离职预测
    共享单车租赁需求预测
    蓝桥杯 区间k大数查询
    蓝桥杯 猴子吃包子
    java计算程序运行时间
    leetcode 185周周赛 字节专场
  • 原文地址:https://www.cnblogs.com/zsbzsb/p/11764045.html
Copyright © 2011-2022 走看看