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.

  1. Given parameters a, b, add edges between points (i, j) and (i, j + 1) for all a ≤ i ≤ b and 1 ≤ j < m.
  2. 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 nm and q.

The i-th of the following q lines contains three integers tiai and bi where ti is the kind of the operation i and aibi 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;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Wuliwuliii

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值