[牛客] [# 1108 E] Grid

2019牛客国庆集训派对day3

链接:https://ac.nowcoder.com/acm/contest/1108/E
来源:牛客网

题意

在一个$10 ^ 9 * 10 ^ 9$ 的方格中,每次把$[l, r]$的每一行整行连通(行间没关系),或者把$[l, r]$列连通,输出连通块的个数,操作为$10 ^ 5$ 次。

思路

本题有个重要的特性,只要有一个行连通和列连通的操作后,之后的连通块就两种情况,一是各个单独成块的小格子,还有就是一个大连通块。

 我:先离散化,对行和列各搞了一个线段树,每次修改看影响了多少个单独的格子,在上次的答案中去掉即可,然后在线段树中标记去掉的列或行。

// #pragma GCC optimize(2)
// #pragma GCC optimize(3)
// #pragma GCC optimize(4)
#include <algorithm>
#include  <iterator>
#include  <iostream>
#include   <cstring>
#include   <cstdlib>
#include   <iomanip>
#include    <bitset>
#include    <cctype>
#include    <cstdio>
#include    <string>
#include    <vector>
#include     <stack>
#include     <cmath>
#include     <queue>
#include      <list>
#include       <map>
#include       <set>
#include   <cassert>
//#include <unordered_set>
//#include <unordered_map>
// #include<bits/extc++.h>
// using namespace __gnu_pbds;
using namespace std;
#define pb push_back
#define fi first
#define se second
#define debug(x) cerr<<#x << " := " << x << endl;
#define bug cerr<<"-----------------------"<<endl;
#define FOR(a, b, c) for(int a = b; a <= c; ++ a)

typedef long long ll;
typedef long double ld;
typedef pair<int, int> pii;
typedef pair<ll, ll> pll;

const int inf = 0x3f3f3f3f;
const ll inff = 0x3f3f3f3f3f3f3f3f;
const int mod = 1e9+7;


template<typename T>
inline T read(T&x){
    x=0;int f=0;char ch=getchar();
    while (ch<'0'||ch>'9') f|=(ch=='-'),ch=getchar();
    while (ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
    return x=f?-x:x;
}

/**********showtime************/
            const int maxn = 1e5+9;

            struct Q{
                int tp;
                int a, b;
            } qu[maxn];

            struct Tree{
                vector<int>vec;
                int getid(int x) {
                    return lower_bound(vec.begin(), vec.end(), x) - vec.begin() + 1;
                }
                int N;
                void init(int n) {
                    vec.pb(1);
                    vec.pb(n+1);
                    sort(vec.begin(), vec.end());
                    vec.erase(unique(vec.begin(), vec.end()), vec.end());
                    N = vec.size() ;
                }
                ll sum[maxn << 2];
                ll lazy[maxn << 2];
                void build(int le, int ri, int rt, int val) {
                    lazy[rt] = -1;
                    if(le == ri) {
                        if(le < vec.size()) {
                            sum[rt] = 1ll * (vec[le] - vec[le-1] ) * val;
                        }
                        else sum[rt] = 0;
                        return;
                    }
                    int mid = (le + ri) >> 1;
                    build(le, mid, rt<<1, val);
                    build(mid+1, ri, rt<<1|1, val);
                    sum[rt] = sum[rt<<1] + sum[rt<<1|1];
                }
                void pushdown(int le, int ri, int rt) {
                    lazy[rt<<1] = lazy[rt<<1|1] = lazy[rt];
                    sum[rt<<1] = sum[rt<<1|1] = 0;
                    lazy[rt] = -1;
                }
                void update(int L, int R, int val, int le, int ri, int rt) {
                    if(le >= L && ri <= R) {
                        lazy[rt] = val;
                        sum[rt] = 0;
                        return;
                    }
                    if(lazy[rt] != -1) pushdown(le, ri, rt);
                    int mid = (le + ri) >> 1;
                    if(mid >= L) update(L, R, val, le, mid, rt<<1);
                    if(mid < R) update(L, R, val, mid+1, ri, rt<<1|1);
                    sum[rt] = sum[rt<<1] + sum[rt<<1|1];
                }
                int query(int L, int R, int le, int ri, int rt) {
                    if(le >= L && ri <= R) {
                        return sum[rt];
                    }
                    if(lazy[rt] != -1) pushdown(le, ri, rt);
                    int mid = (le + ri) >> 1;
                    int res = 0;
                    if(mid >= L) res += query(L, R, le, mid, rt<<1);
                    if(mid < R) res += query(L ,R, mid+1, ri, rt<<1|1);
                    return res;
                }
            } tr[2];
int main(){
            int n,m,q;
            while(~scanf("%d%d%d", &n, &m, &q)) {
                tr[0].vec.clear();
                tr[1].vec.clear();
                for(int i=1; i<=q; i++) {
                    scanf("%d%d%d", &qu[i].tp, &qu[i].a, &qu[i].b);
                    qu[i].tp --;
                    tr[qu[i].tp].vec.pb(qu[i].a);
                    tr[qu[i].tp].vec.pb(qu[i].b+1);
                }
                tr[0].init(n);
                tr[1].init(m);

                tr[0].build(1, tr[0].N, 1, 1);
                tr[1].build(1, tr[1].N, 1, 1);


                int pretp = -1, flag = 1;
                int wai = 0;
                ll ans = 1ll*n * m;


                for(int i=1; i<=q; i++) {
                    int tp = qu[i].tp, a = qu[i].a, b = qu[i].b;
                    if(pretp != -1 && flag && pretp != tp) {
                        wai = 1;
                        flag = 0;
                    }
                    if(tp == 0) {
                        ll k = tr[1].sum[1];
                        ans -= 1ll*(tr[0].query(tr[0].getid(qu[i].a), tr[0].getid(qu[i].b + 1) - 1, 1, tr[0].N, 1)) * k;
                        if(flag) wai += tr[0].query(tr[0].getid(qu[i].a), tr[0].getid(qu[i].b + 1) - 1, 1, tr[0].N, 1);
                        tr[0].update(tr[0].getid(qu[i].a), tr[0].getid(qu[i].b + 1) - 1, 0, 1, tr[0].N, 1);
                    }
                    else {
                        ll k = tr[0].sum[1];
                        ans -= 1ll*(tr[1].query(tr[1].getid(qu[i].a), tr[1].getid(qu[i].b + 1) - 1, 1, tr[1].N, 1)) * k;
                        if(flag) wai += tr[1].query(tr[1].getid(qu[i].a), tr[1].getid(qu[i].b + 1) - 1, 1, tr[1].N, 1);
                        tr[1].update(tr[1].getid(qu[i].a), tr[1].getid(qu[i].b + 1) - 1, 0, 1, tr[1].N, 1);
                    }
                    pretp = tp;
                    printf("%lld\n", ans + wai);
                }
            }
            return 0;
}
View Code

神人:线段树动态开点,保存有几行被连通了,有几列被连通了。每次单独计算:当行和列同时有被连通,不管形态,他们占领的格子是固定的。

#include<bits/stdc++.h>
using namespace std;
 
typedef long long ll;
const int maxn=1e5+7;
 
struct Tree{
    int lc,rc,sum;
}a[maxn*26];
int tot;
int build(){
    int k=++tot;
    a[k].lc=a[k].rc=a[k].sum=0;
    return k;
}
 
void insert(int p,int l,int r,int L,int R){
    if(a[p].sum==r-l+1) return ;
    if(l>=L&&r<=R){
        a[p].sum=r-l+1;
        return ;
    }
    int mid=(l+r)>>1;
    if(L<=mid){
        if(!a[p].lc) a[p].lc=build();
        insert(a[p].lc,l,mid,L,R);
    }
    if(R>mid){
        if(!a[p].rc) a[p].rc=build();
        insert(a[p].rc,mid+1,r,L,R);
    }
    a[p].sum=a[a[p].lc].sum+a[a[p].rc].sum;
}
 
int main(){
    int n,m,q,rtrow,rtcal,id,l,r;
    ll res;
    while(scanf("%d%d%d",&n,&m,&q)!=EOF){
        tot=0;
        rtrow=build();
        rtcal=build();
        while(q--){
            scanf("%d%d%d",&id,&l,&r);
            if(id==1) insert(rtrow,1,n,l,r);
            else insert(rtcal,1,m,l,r);
            res=0;
            if(a[rtrow].sum==0) res=(m-a[rtcal].sum)*1LL*n+a[rtcal].sum;
            else if(a[rtcal].sum==0) res=(n-a[rtrow].sum)*1LL*m+a[rtrow].sum;
            else{
                res=n*1LL*m-a[rtrow].sum*1LL*m-a[rtcal].sum*1LL*n+a[rtrow].sum*1LL*a[rtcal].sum+1;
            }
            printf("%lld\n",res);
        }
    }
 
    return 0;
}
View Code

 

posted @ 2019-10-04 16:10  ckxkexing  阅读(141)  评论(0编辑  收藏  举报