LG7721 [Ynoi2007] rcn 【莫队,分块】
矩形颜色数,带权,不强制在线。
对一维莫队,问题变为 \(\mathcal O(1)\) 单点修改 \(\mathcal O(\sqrt n)\) 求区间颜色权值和,转化为 \((i,\text{pre}_i)\) 的二维数点,为了方便维护 \(\text{pre}_i\),使用不加入莫队,特判 \(\text{pre}_i\) 不存在的情况之后就是不重的,套用 rdiq 的分块方法即可。
时间复杂度 \(\mathcal O(n\sqrt m+m\sqrt n)\),空间复杂度 \(\mathcal O(n+m)\)。
#include<bits/stdc++.h>
using namespace std;
const int N = 1e5 + 5, M = 1e6 + 5, B0 = 18, B1 = B0 * B0, B2 = B0 * B1;
int n, m, B, p[N], ip[N], a[N], pre[N], nxt[N], tmp[N];
unsigned b[N], ans[M];
bool del[N];
struct Node {
int l1, r1, l2, r2, id;
Node(int _1 = 0, int _2 = 0, int _3 = 0, int _4 = 0, int _5 = 0):
l1(_1), r1(_2), l2(_3), r2(_4), id(_5){}
bool operator < (const Node &o) const {return r1 > o.r1;}
};
vector<Node> rqy[1005];
struct BIT {
unsigned sum[B1], val[N];
void clear(){
memset(sum, 0, sizeof(sum));
memset(val, 0, (n + 1) << 2);
}
void upd(int p, unsigned v){sum[p / B1] += v; val[p] += v;}
unsigned qry(int p){
unsigned res = 0;
for(int i = p / B1 - 1;i >= 0;-- i) res += sum[i];
for(int i = p / B1 * B1;i <= p;++ i) res += val[i];
return res;
}
} t1, t2;
unsigned s0[B0][B0], s1[B1][B0], s2[B0][B1], s3[B1][B1];
void clear(){
t1.clear(); t2.clear();
memset(s0, 0, sizeof(s0));
memset(s1, 0, sizeof(s1));
memset(s2, 0, sizeof(s2));
memset(s3, 0, sizeof(s3));
memset(pre, 0, (n + 1) << 2);
memset(nxt, 0, (n + 1) << 2);
memset(tmp, 0, (n + 1) << 2);
memset(del, 1, n + 1);
}
void upd(int x, unsigned v){
t1.upd(x, v); int y = pre[x];
if(y){
s0[x / B2][y / B2] += v;
s1[x / B1][y / B2] += v;
s2[x / B2][y / B1] += v;
s3[x / B1][y / B1] += v;
} else t2.upd(x, v);
}
unsigned qry(int x, int y){
int xl = x / B1 * B1, yl = y / B1 * B1;
unsigned res = t2.qry(x) - t1.qry(y);
for(int i = xl;i <= x;++ i) if(!del[i] && pre[i] && pre[i] <= y) res += t1.val[i];
for(int i = yl;i <= y;++ i) if(!del[i] && nxt[i] && nxt[i] < xl) res += t1.val[nxt[i]];
x = x / B1 - 1; y = y / B1 - 1;
for(int i = x / B0 - 1;i >= 0;-- i)
for(int j = y / B0 - 1;j >= 0;-- j) res += s0[i][j];
for(int i = x / B0 * B0;i <= x;++ i)
for(int j = y / B0 - 1;j >= 0;-- j) res += s1[i][j];
for(int i = x / B0 - 1;i >= 0;-- i)
for(int j = y / B0 * B0;j <= y;++ j) res += s2[i][j];
for(int i = x / B0 * B0;i <= x;++ i)
for(int j = y / B0 * B0;j <= y;++ j) res += s3[i][j];
return res;
}
void rem(int x){
upd(p[x], -b[a[x]]);
if(nxt[p[x]]){upd(nxt[p[x]], -b[a[x]]); pre[nxt[p[x]]] = pre[p[x]]; upd(nxt[p[x]], b[a[x]]);}
if(pre[p[x]]) nxt[pre[p[x]]] = nxt[p[x]];
del[p[x]] = 1;
}
void undo(int x){
upd(p[x], b[a[x]]);
if(nxt[p[x]]){upd(nxt[p[x]], -b[a[x]]); pre[nxt[p[x]]] = p[x]; upd(nxt[p[x]], b[a[x]]);}
if(pre[p[x]]) nxt[pre[p[x]]] = p[x];
del[p[x]] = 0;
}
int main(){
ios::sync_with_stdio(0);
cin >> n;
for(int i = 1;i <= n;++ i){cin >> p[i]; ip[p[i]] = i;}
for(int i = 1;i <= n;++ i) cin >> a[i];
for(int i = 1;i <= n;++ i) cin >> b[i];
cin >> m; B = n / sqrt(m) + 1;
for(int i = 1, l1, r1, l2, r2;i <= m;++ i){
cin >> l1 >> r1 >> l2 >> r2;
rqy[(l1 - 1) / B].emplace_back(l1, r1, l2, r2, i);
}
for(int _ = 0;_ * B < n;++ _) if(!rqy[_].empty()){
sort(rqy[_].begin(), rqy[_].end()); clear();
for(int i = 1;i <= n;++ i) if(ip[i] > _ * B){
pre[i] = tmp[a[ip[i]]]; tmp[a[ip[i]]] = i; upd(i, b[a[ip[i]]]); del[i] = 0;
}
for(int i = 1;i <= n;++ i) if(ip[i] > _ * B && pre[i]) nxt[pre[i]] = i;
int now = n;
for(auto [l1, r1, l2, r2, id] : rqy[_]){
for(;now > r1;-- now) rem(now);
for(int j = _ * B + 1;j < l1;++ j) rem(j);
ans[id] = qry(r2, l2 - 1);
for(int j = l1 - 1;j > _ * B;-- j) undo(j);
}
}
for(int i = 1;i <= m;++ i) cout << ans[i] << '\n';
}