zoukankan      html  css  js  c++  java
  • [牛客] [# 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
    ", 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
    ",res);
            }
        }
     
        return 0;
    }
    View Code
  • 相关阅读:
    Tips on Hair and Final gathering
    数学公式和符号的念法
    How to use Intel C++ Compiler in Visual Studio 2008
    Number Prefixes in Mathematics
    Glossy reflections/refractions in large scene
    atomic flushing data
    elvish Template Library Plan
    [Maxim07]中光线与三角形求交算法的推导
    C# 关闭窗体立即停止进程
    MS SQL 索引设计的准则
  • 原文地址:https://www.cnblogs.com/ckxkexing/p/11622338.html
Copyright © 2011-2022 走看看