欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Grid【可持久化线段树】【2018湖南省第14届大学生计算机程序设计竞赛】

程序员文章站 2024-03-03 16:58:16
...

题目链接


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;
}

 

相关标签: 可持久化线段树