2021ZJCPC G.Wall Game(并查集+思维)
·
简要题意:
昨天写了原题,有感,故有此题解🤭
本题有两个操作:
1.attack–>占领(x,y),意味着消除和周围已经占领的坐标之间的墙
2.query–>查询(x,y)所在连通块有多少面墙
这两个需求都可以用并查集来维护
数据结构:
我们可以封装一个并查集类,支持查找,合并,返回必要的值
class DSU {
private:
int n;
std::vector<int> f,sz,rst;
public:
inline void init(int n_) {
this->n = n_;
f.assign(n+1,0); sz.assign(n+1,1); rst.assign(n+1,0);
std::iota(f.begin(),f.end(),0);
}
int find(int u) {
return f[u] == u ? u : f[u] = find(f[u]);
}
void merge(const int u,const int v) {
int fu = find(u),fv = find(v);
if (fu != fv) {
f[fv] = fu; sz[fu] += sz[fv]; rst[fu] += rst[fv] + 2;
}else rst[fu] += 2;
}
int get_sz(int pos) { return this->sz[pos]; }
int get_rst(int pos) { return this->rst[pos]; }
}dsu;
处理技巧:
由于本题是二维坐标,我们需要用std::map来动态地为每个坐标开点,将二维坐标转换为线性的一维坐标.
mp[{x,y}] = ++cnt;
答案统计:
对于查询的坐标(x,y),如果(x,y)所在的连通块只有它自己,那么答案就是6.为什么呢?
原因很简单,因为(x,y)附近的点都没有被攻击,所以(x,y)的六条边都不会被消除
否则:答案就是6 * (x,y)所在的连通块的点的数量 - 2 * 重复的数量(本题的核心)
完整代码(已经AC):
#include <bits/stdc++.h>
using ll = long long signed int;
#define lowbit(x) ((x)&-(x))
#define pi std::acos(-1.0)
#define pii std::pair<int,int>
#define mst(x) std::memset(x,0,sizeof(x))
#define IOS std::ios::sync_with_stdio(false),std::cin.tie(0),std::cout.tie(0)
#define mid ((l+r)>>1)
const int inf = 0x3f3f3f3f;
const ll linf = 0x3f3f3f3f3f3f3f3f;
const int N = 500005;
class DSU {
private:
int n;
std::vector<int> f,sz,rst;
public:
inline void init(int n_) {
this->n = n_;
f.assign(n+1,0); sz.assign(n+1,1); rst.assign(n+1,0);
std::iota(f.begin(),f.end(),0);
}
int find(int u) {
return f[u] == u ? u : f[u] = find(f[u]);
}
void merge(const int u,const int v) {
int fu = find(u),fv = find(v);
if (fu != fv) {
f[fv] = fu; sz[fu] += sz[fv]; rst[fu] += rst[fv] + 2;
}else rst[fu] += 2;
}
int get_sz(int pos) { return this->sz[pos]; }
int get_rst(int pos) { return this->rst[pos]; }
}dsu;
int cnt;
int nxts[][2] = {1,0,1,-1,0,-1,-1,0,-1,1,0,1};
std::map<pii,int> mp;
void solve();
int main() {
IOS; int T = 1;
while (T--) solve();
return 0;
}
void solve() {
int q; std::cin >> q;
dsu.init(q);
while (q--) {
int op,x,y; std::cin >> op >> x >> y;
if (op == 1) {
mp[{x,y}] = ++cnt;
for (int i = 0; i < 6; ++i) {
int tx = x + nxts[i][0];
int ty = y + nxts[i][1];
if (mp.find({tx,ty}) == mp.end()) continue;
dsu.merge(cnt,mp[{tx,ty}]);
}
}
else if (op == 2) {
int fx = dsu.find(mp[{x,y}]);
if (dsu.get_sz(fx) == 1) std::cout << 6 << "\n";
else std::cout << (6 * dsu.get_sz(fx) - dsu.get_rst(fx)) << "\n";
}
}
}
更多推荐
所有评论(0)