atc abc461E 思路分享(树状数组)

https://atcoder.jp/contests/abc461/tasks/abc461_e

题意

\(n\times n\) 网格中,初始所有块均为白色.

\(q\) 个查询,每个查询会将某行全部染成黑色,或者将某列全部染成白色,每个查询操作完成后输出黑色块数量.

\(1\le n,q \le 3\times 10^5\).

思路

\(R_i\) 为第 \(i\) 行最后一次被染成黑色的时间,\(C_j\) 为第 \(j\) 列最后一次被染成白色的时间,每个格子的颜色取决与 \(R_i\)\(C_j\) 的大小关系.

观察一次操作的影响,仅讨论行操作,列操作是类似的.

将行 \(x\) 染成黑色,增量为行 \(x\) 当前为白色的格子,记行 \(x\) 上次被染成黑色的时间为 \(pre\),即统计 \(C_j\gt pre\) 的列数量,这显然可以通过树状数组维护.

时间复杂度 \(\mathcal{O}(n\log n)\).

代码

//author:kzssCCC

#include <bits/stdc++.h>
using namespace std;
using ll = long long;

struct fenwick{
    int n;
    vector<int> a;

    fenwick(int _n){
        n = _n;
        a.assign(n+1,0);
    }    

    void update(int pos,int val){
        for (int i=pos;i<=n;i+=i&-i){
            a[i] += val;
        }
    }

    int query(int pos){
        int res = 0;
        for (int i=pos;i>=1;i-=i&-i){
            res += a[i];
        }
        return res;
    }

    int query_range(int l,int r){
        return query(r)-query(l-1);
    }
};

void solve(){
    int n,q;
    cin >> n >> q;

    vector<int> R(n+1,-1),C(n+1);
    fenwick fwR(q+1),fwC(q+1);
    fwC.update(1,n);
    ll res = 0;

    for (int t=1;t<=q;t++){
        int op,x;
        cin >> op >> x;
        if (op==1){
            int pre = R[x];
            res += fwC.query_range(pre+2,q+1);
            if (pre>=0){
                fwR.update(pre+1,-1);
            }
            fwR.update(t+1,1);
            R[x] = t;
        }
        else{
            int pre = C[x];
            res -= fwR.query_range(pre+2,q+1);
            fwC.update(pre+1,-1);
            fwC.update(t+1,1);
            C[x] = t;
        }
        cout << res << '\n';
    }    
}

int main(){
    ios::sync_with_stdio(false);
    cin.tie(0);
    
    int t = 1;
    // cin >> t;
    while (t--) solve();

    return 0;
}
posted @ 2026-08-01 18:39  kzssCCC  阅读(12)  评论(0)    收藏  举报