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

浙公网安备 33010602011771号