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';
}
posted @ 2022-07-20 19:18  mizu164  阅读(64)  评论(0编辑  收藏  举报