二次离线莫队

更新答案不是 \(O(1)\)?答案可差分?

二离来啦。

P4887 【模板】莫队二次离线

先考虑贡献:\(f(x,[l,r])\) 表示 \(x\) 对区间 \([l,r]\)

考虑莫队每次的移动:\(r\to r'\)。答案增加为:

\[\sum_{i\in [r+1,r']} f(i,[l,i-1])=\sum_{i\in [r+1,r']} f(i,[1,i-1])-f(i,[1,l-1]) \]

发现前面那一坨可以直接预处理,莫队的时候 \(O(1)\) 更新即可。考虑后面。

\(g([r+1,r'],[1,l-1])\) 表示 \(\sum\limits_{i\in [r+1,r']} f(i,[1,l-1])=\sum\limits_{i<l} f(i,[r+1,r'])\)

又,由莫队的复杂度证明知,所有 \([r+1,r']\) 的长度总和在线性根号级别。所以我们可以对 \(i\) 递增扫描线,每次更新前缀值,然后在 \([r+1,r']\) 暴力查询即可。

对于单点,查询怎么做?套路地开一个桶记录即可。单次复杂度为 \(O(\binom{14}{k})\),最大为 3000 多一点。

注意上面只列举了 \(r\to r'\) 的情况,其它情况是平凡的。

#include <bits/stdc++.h>
#define pb push_back
#define pii pair <int, int> 
#define int long long
using namespace std;
const int N = 2e5 + 5; int read();

int n, m, k, pre[N], a[N], blo;
vector <int> ton; int b[N], ans[N]; // b 

struct node {
	int l, r, id;
	friend bool operator < (node a, node b) {
		if(a.l / blo == b.l / blo) return (a.l / blo) & 1 ? a.r < b.r : a.r > b.r;
		return a.l < b.l;
	} 
} p[N];

struct sb { 
	int l, r, id, op; 
	sb (int a, int b, int c, int d) { l = a, r = b, id = c, op = d; }
};
vector <sb> G[N];

signed main() {
	cin >> n >> m >> k; blo = sqrt(n);
	for(int i = 1;i <= n; ++i) a[i] = read();
	for(int i = 0;i < 16384; ++i) if(__builtin_popcount(i) == k) ton.pb(i);
	
	for(int i = 1;i <= n; ++i) {
		pre[i] = b[a[i]] + pre[i - 1];
		for(int j : ton) b[j ^ a[i]] ++;
	}
	
	for(int i = 1;i <= m; ++i) p[i].l = read(), p[i].r = read(), p[i].id = i;
	sort(p + 1, p + m + 1); int l = 1, r = 0;
	
	for(int i = 1;i <= m; ++i) {  // 顺序任意 
		int id = p[i].id, L = p[i].l, R = p[i].r;
		// 删除
		if(l < L) { // i[l, L-1]  [i,r]
			ans[id] += pre[L - 1] - pre[l - 1];
			G[r].pb(sb(l, L - 1, id, -1));
			l = L;
		} if(r > R) { // i[R+1,r]  [l,i]
			ans[id] -= pre[r] - pre[R];
			G[l - 1].pb(sb(R + 1, r, id, 1));
			r = R;
		} 
		// 加入
		if(l > L) { // i[L, l-1]  [i, r]
			ans[id] -= pre[l - 1] - pre[L - 1];
			G[r].pb(sb(L, l - 1, id, 1));
			l = L;
		} if(r < R) { // i[r+1, R] [l, i]
			ans[id] += pre[R] - pre[r];
			G[l - 1].pb(sb(r + 1, R, id, -1));
			r = R;
		}
	}
	memset(b, 0, sizeof b);
	for(int i = 1;i <= n; ++i) {
		for(int to : ton) b[to ^ a[i]] ++;
		for(auto it : G[i]) {
			int l = it.l, r = it.r, id = it.id, op = it.op;
			for(int j = l;j <= r; ++j) ans[id] += op * (b[a[j]] - (k == 0 and j <= i));
		}
	}
	
	for(int i = 1;i <= m; ++i) ans[p[i].id] += ans[p[i - 1].id];
	for(int i = 1;i <= m; ++i) printf("%lld\n", ans[i]);		
	return 0;
}

int read() {
   char c; int f = 1, sum = 0;
   while(c < '0' or c > '9') {if(c == '-') f = -1;c = getchar();}
   while(c >= '0' and c <= '9') {sum = (sum << 3) + (sum << 1) + (c ^ 48);c = getchar();} 
   return sum * f;
}

posted @ 2024-07-20 11:32  LCat90  阅读(3)  评论(0编辑  收藏  举报