题意:
op1 攻占x,y这个块,并且在没有被攻占的邻块之间修一道墙。
op2 询问x ,y可以理解为一个人在这个块开始走,并且可以走向联通的块他最多可以触碰到几块墙壁。
举个栗子
我们占领 (0,1)(1,1)(1,-1)这三个块,我们会得到以下情况
我们访问(0,1)那么答案就是10
我们访问(1,-1)那么答案就是6
思路的化就是用并查集,并维护并查集祖先节点的值,(该值就是此联通块的周长,每加入一块就更新一下)
#include <iostream>
#include<algorithm>
#include<cstring>
#include<queue>
#include<map>
#define TLE std::ios::sync_with_stdio(false)
using namespace std;
typedef long long ll;
typedef pair<long long ,long long >PII;
const int INF = 0x3f3f3f3f;
const int N = 5e5 + 10;
map<PII, ll>mp;
ll tot;
ll p[N], ans[N];
ll find(ll x)
{
if (x != p[x])p[x] = find(p[x]);
return p[x];
}
void work(PII t)
{
ans[mp[t]] = 6;//初始化该块的边数
ll d[6][2] = { {0,1},{1,0},{1,-1},{0,-1},{-1,0},{-1,1} };//六个遍历方向
for (int i = 0; i < 6; i++)
{
ll x = t.first + d[i][0], y = t.second + d[i][1];
PII now = make_pair(x, y);
if (mp[now])//如果邻块被占领
{
ll a = find(mp[t]), b = find(mp[now]);
if (a != b)//如果两个连通块祖先不同则合并两个块,并维护祖先节点的ans
{
p[a] = b;
ans[b] += ans[a] - 2;
}
else ans[b] -= 2;
/*如果两块已经联通,则该联通块失去两块墙壁
此情况出现在t这块向其他方向遍历时已经被并入
然后在该方向上是联通的所以变数-2*/
}
}
}
int main()
{
TLE;//数据量很大,关闭同步流
tot = 0;
ll op,x, y,_;
cin >> _;
for (int i = 1; i <= _; i++)p[i] = i;//并查集初始化
while (_--)
{
cin >> op>>x>>y;
if (op == 1)
{
PII t = make_pair(x, y);//将坐标映射为一个int值
mp[t] = ++tot;
work(t);
}
else if (op == 2)
{
PII t = make_pair(x, y);
cout << ans[find(mp[t])] << endl;
}
}
return 0;
}