[Problem Description]
![](http://www.lydsy.com/JudgeOnline/upload/201305/1%2814%29.jpg)
[Algorithm]
线段树 并查集
[Analysis]
写在最前面的话:
这真是我写过的最蛋疼的线段树!
求联通块,区间查询,点修改——线段树+并查集的节奏。很好……具体怎么做呢?真是一个蛋疼的问题……每个线段树节点维护这一片的联通块数量,和这一片两端边界的并查集以及每个集是否与某个O联通。处理宽度为1的时候的线段树节点,就是扫一遍维护一下并查集以及是否与O联通。合并两个儿子是麻烦的。需要将两个儿子的四个边界放到一起,然后通过相邻的那两条边界去更新并查集,同时一旦合并两个都与O联通的集,ans就减一。最后要更改并查集中的信息——因为最后留下来的只有两侧的边界,中间的那两个边界是不会出现的。所以将那些根节点位于中间的集的根更改一下。修改和查询与普通的线段树是一样的。
[Pay Attention]
内存要紧着点开……
[Code]
/**************************************************************
Problem: 3204
User: gaotianyu1350
Language: C++
Result: Accepted
Time:2592 ms
Memory:47276 kb
****************************************************************/
#include <cstdio>
#include <cstring>
#include <cmath>
#include <cstdlib>
#include <iostream>
using namespace std;
const int MAXN = 100010;
const int MAXM = 7;
const int HENG = 0;
const int SHU = 1;
int n, m, q;
char map[MAXN][MAXM];
struct SegNode
{
int cnt;
int f[MAXM * 2], able[MAXM * 2];
SegNode()
{
cnt = 0;
memset(f, 0, sizeof(f));
memset(able, 0, sizeof(able));
}
} seg[MAXN * 4];
inline bool isok(char c, int ty)
{
if (ty == HENG)
{
if (c == 'O' || c == '-' || c == '+') return true;
else return false;
}
else
{
if (c == 'O' || c == '|' || c == '+') return true;
else return false;
}
}
int getfather(int *f, int now)
{
return f[now] == now ? now : (f[now] = getfather(f, f[now]));
}
inline void DealwithSingle(int now, int h)
{
int *t = seg[now].f;
int *a = seg[now].able;
for (int i = 1; i <= m; i++)
{
t[i] = i;
a[i] = map[h][i] == 'O' ? 1 : 0;
}
for (int i = 1; i < m; i++)
if (isok(map[h][i], HENG) && isok(map[h][i + 1], HENG))
{
t[i] = i + 1;
a[i + 1] |= a[i];
}
seg[now].cnt = 0;
bool check[MAXM] = {0};
for (int i = 1; i <= m; i++)
{
int gf = getfather(t, i);
if (!check[gf] && a[gf])
seg[now].cnt++;
check[gf] = true;
}
for (int i = m + 1; i <= 2 * m; i++)
t[i] = i - m;
}
inline int update(int mid, int cnt1, int cnt2, int *f1, int *f2, int *a1, int *a2, int *ftar, int *atar)
{
int f[MAXM * 4] = {0}, a[MAXM * 4] = {0};
for (int i = 1; i <= m * 2; i++)
{
f[i] = f1[i];
f[i + m * 2] = f2[i] + m * 2;
a[i] = a1[i];
a[i + m * 2] = a2[i];
}
int ans = cnt1 + cnt2;
for (int i = 1; i <= m; i++)
{
if (isok(map[mid][i], SHU) && isok(map[mid + 1][i], SHU))
{
int sf = getfather(f, m + i);
int gf = getfather(f, m * 2 + i);
if (sf == gf) continue;
if (a[sf] && a[gf]) ans--;
f[gf] = sf;
a[sf] |= a[gf];
}
}
for (int i = 1; i <= m; i++)
{
ftar[i] = getfather(f, i);
atar[i] = a[ftar[i]];
ftar[i + m] = getfather(f, m * 3 + i);
atar[i + m] = a[ftar[i + m]];
}
memset(f, 0, sizeof(f));
for (int i = 1; i <= m; i++)
{
if (!f[ftar[i]]) f[ftar[i]] = i;
if (!f[ftar[i + m]]) f[ftar[i + m]] = i + m;
}
for (int i = 1; i <= m; i++)
{
ftar[i] = f[ftar[i]];
ftar[i + m] = f[ftar[i + m]];
}
return ans;
}
void build(int now, int left, int right)
{
if (left == right)
{
DealwithSingle(now, left);
return;
}
int mid = (left + right) >> 1;
build(now << 1, left, mid);
build((now << 1) + 1, mid + 1, right);
seg[now].cnt = update(mid, seg[now << 1].cnt, seg[(now << 1) + 1].cnt,
seg[now << 1].f , seg[(now << 1) + 1].f,
seg[now << 1].able, seg[(now << 1) + 1].able,
seg[now].f, seg[now].able);
}
void change(int now, int left, int right, int x)
{
if (left == right)
{
DealwithSingle(now, left);
return;
}
int mid = (left + right) >> 1;
if (x <= mid)
change(now << 1, left, mid, x);
else
change((now << 1) + 1, mid + 1, right, x);
seg[now].cnt = update(mid, seg[now << 1].cnt, seg[(now << 1) + 1].cnt,
seg[now << 1].f , seg[(now << 1) + 1].f,
seg[now << 1].able, seg[(now << 1) + 1].able,
seg[now].f, seg[now].able);
}
int query(int now, int left, int right, int l, int r, int *tf, int *ta)
{
if (l <= left && right <= r)
{
memmove(tf + 1, seg[now].f + 1, sizeof(int) * m * 2);
memmove(ta + 1, seg[now].able + 1, sizeof(int) * m * 2);
return seg[now].cnt;
}
int mid = (left + right) >> 1;
if (r <= mid)
return query(now << 1, left, mid, l, r, tf, ta);
else if (l > mid)
return query((now << 1) + 1, mid + 1, right, l, r, tf, ta);
else
{
int mlf[MAXM * 2], mrf[MAXM * 2], mla[MAXM * 2], mra[MAXM * 2];
int cnt1 = query(now << 1, left, mid, l, r, mlf, mla);
int cnt2 = query((now << 1) + 1, mid + 1, right, l, r, mrf, mra);
return update(mid, cnt1, cnt2, mlf, mrf, mla, mra, tf, ta);
}
}
int main()
{
int tempf[MAXM * 2];
int tempa[MAXM * 2];
//freopen("input.txt", "r", stdin);
//freopen("output.txt", "w" ,stdout);
scanf("%d%d", &n, &m);
for (int i = 1; i <= n; i++)
for (int j = 1; j <= m; j++)
scanf(" %c", &map[i][j]);
build(1, 1, n);
scanf("%d", &q);
for (int i = 1; i <= q; i++)
{
char order;
scanf(" %c", &order);
if (order == 'C')
{
int x, y;
char k;
scanf("%d%d %c", &x, &y, &k);
map[x][y] = k;
change(1, 1, n, x);
}
else
{
int left, right;
scanf("%d%d", &left, &right);
int ans = query(1, 1, n, left, right, tempf, tempa);
printf("%d\n", ans);
}
}
}