Grid【可持久化线段树】【2018湖南省第14届大学生计算机程序设计竞赛】
题目链接
Description
Bobo has n × m points arranged into a matrix with n rows and m columns. The points in the intersection of the i-th row and the j-th column is labeled with (i, j). He is going to perform q operations of the following 2 kinds.
- Given parameters a, b, add edges between points (i, j) and (i, j + 1) for all a ≤ i ≤ b and 1 ≤ j < m.
- Given parameters a, b, add edges between points (i, j) and (i + 1, j) for all 1 ≤ i < n and a ≤ j ≤ b.
Bobo would like to know the number of connected components after each operation.
- 1 ≤ n, m ≤ 109
- 1 ≤ q ≤ 105
- ti ∈ {1, 2}
- If ti = 1, 1 ≤ ai ≤ bi ≤ n. If ti = 2, 1 ≤ ai ≤ bi ≤ m.
- The sum of q does not exceed 5 × 105.
Input
The input consists of several test cases and is terminated by end-of-file.
The first line of each test case contains three integers n, m and q.
The i-th of the following q lines contains three integers ti, ai and bi where ti is the kind of the operation i and ai, bi are corresponding parameters.
Output
For each test case, print q integers which denote the number of connected components after each operation.
Sample Input
2 3 3 2 1 1 2 3 3 1 1 1 1000000000 1000000000 1 1 1 2
Sample Output
5 4 2 999999998000000002
Hint
Source
2018湖南省第14届大学生计算机程序设计竞赛
题意:我们一开始有N*M个相互独立的点,然后我们有两种操作,利用(i,j)表示点,操作1将i从a到b的每个横排链接,操作2将j从a到b的每一竖都贯穿了。也就是说操作1贯穿y轴,操作2打通x轴,使得对应行列的点链接在了一起。
思路:一开始就是比比画画,然后当我画了一副3*4的矩阵图之后就发现了这么一个规律,当我们只有x轴方向上的或者是y轴方向上的,那么此时的联通点的数目是跟打通了几排有关,最后再加上这几排即可;当x轴和y轴方向上都有的时候,我们此时用到了一个冗斥定理,我们先加上全体,然后再去减去一部分,再把多减的部分加回来,最后因为它自己也构成了一个联通点,所以末尾还需要再加1。
#include <iostream>
#include <cstdio>
#include <cmath>
#include <string>
#include <cstring>
#include <algorithm>
#include <limits>
#include <vector>
#include <stack>
#include <queue>
#include <set>
#include <map>
#define lowbit(x) ( x&(-x) )
#define pi 3.141592653589793
#define e 2.718281828459045
#define INF 0x3f3f3f3f
#define HalF (l + r)>>1
#define lsn rt<<1
#define rsn rt<<1|1
#define Lson lsn, l, mid
#define Rson rsn, mid+1, r
#define QL Lson, ql, qr
#define QR Rson, ql, qr
#define myself rt, l, r
namespace fastIO {
#define BUF_SIZE 100000
//fread -> read
bool IOerror = 0;
inline char nc() {
static char buf[BUF_SIZE], *p1 = buf + BUF_SIZE, *pend = buf + BUF_SIZE;
if(p1 == pend) {
p1 = buf;
pend = buf + fread(buf, 1, BUF_SIZE, stdin);
if(pend == p1) {
IOerror = 1;
return -1;
}
}
return *p1++;
}
inline bool blank(char ch) {
return ch == ' ' || ch == '\n' || ch == '\r' || ch == '\t';
}
inline void read(int &x) {
char ch;
while(blank(ch = nc()));
if(IOerror) return;
for(x = ch - '0'; (ch = nc()) >= '0' && ch <= '9'; x = x * 10 + ch - '0');
}
#undef BUF_SIZE
};
using namespace fastIO;
using namespace std;
typedef unsigned long long ull;
typedef long long ll;
const int maxN = 1e5 + 7;
int Q, op, a, b, lc1[30*maxN] = {0}, rc1[30*maxN] = {0}, lc2[30*maxN] = {0}, rc2[30*maxN] = {0}, root1, root2, tot1, tot2;
ll N, M, ans, s1[30*maxN] = {0}, s2[30*maxN] = {0};
inline void pushup_1(int rt) { s1[rt] = s1[lc1[rt]] + s1[rc1[rt]]; }
inline void update_1(int &rt, int l, int r, int ql, int qr)
{
if(!rt) rt = ++tot1;
if(s1[rt] == r - l + 1) return;
if(ql <= l && qr >= r)
{
s1[rt] = r - l + 1;
return;
}
int mid = HalF;
if(qr <= mid) update_1(lc1[rt], l, mid, ql, qr);
else if(ql > mid) update_1(rc1[rt], mid + 1, r, ql, qr);
else { update_1(lc1[rt], l, mid, ql, qr); update_1(rc1[rt], mid + 1, r, ql, qr); }
pushup_1(rt);
}
inline void pushup_2(int rt) { s2[rt] = s2[lc2[rt]] + s2[rc2[rt]]; }
inline void update_2(int &rt, int l, int r, int ql, int qr)
{
if(!rt) rt = ++tot2;
if(s2[rt] == r - l + 1) return;
if(ql <= l && qr >= r)
{
s2[rt] = r - l + 1;
return;
}
int mid = HalF;
if(qr <= mid) update_2(lc2[rt], l, mid, ql, qr);
else if(ql > mid) update_2(rc2[rt], mid + 1, r, ql, qr);
else { update_2(lc2[rt], l, mid, ql, qr); update_2(rc2[rt], mid + 1, r, ql, qr); }
pushup_2(rt);
}
inline void init()
{
for(int i=1; i<=tot1; i++) s1[i] = lc1[i] = rc1[i] = 0;
for(int i=1; i<=tot2; i++) s2[i] = lc2[i] = rc2[i] = 0;
root1 = root2 = tot1 = tot2 = 0;
}
int main()
{
tot1 = tot2 = s1[0] = s2[0] = lc1[0] = lc2[0] = rc1[0] = rc2[0] = 0;
while(scanf("%lld%lld%d", &N, &M, &Q)!=EOF)
{
init();
while(Q--)
{
scanf("%d%d%d", &op, &a, &b);
//read(op); read(a); read(b);
if(op == 1) update_1(root1, 1, (int)N, a, b);
else update_2(root2, 1, (int)M, a, b);
if(!s1[1]) ans = (M - s2[1]) * N + s2[1];
else if(!s2[1]) ans = (N - s1[1]) * M + s1[1];
else ans = N * M - (s1[1] * M + s2[1] * N - s1[1] * s2[1]) + 1;
printf("%lld\n", ans);
}
}
return 0;
}