[洛谷P4887] 【模板】莫队二次离线(第十四分块(前体))

前言

考试就指望离谱分块骗分了,还不赶快学!

题目

洛谷

讲解

好嘛,二离刚做完板子,还不是很懂啥时候用,不过看题解区都这么说:

  • 能莫队。
  • 更新不是 \(O(1)\)

然后我们把要更新的区间存下来,在外面跑就行,大概就是这么个意思。

这道题把区间贡献拆成前缀,预处理之后可以快速求贡献。

时间复杂度 \(O(n\sqrt{n}+C_{14}^{k}n)\),看上去比较离谱,但是能过。

代码

//12252024832524
#include <bits/stdc++.h>
#define TT template<typename T>
using namespace std; 

typedef long long LL;
const int MAXN = 100005;
int n,m,k,B;
int a[MAXN];

LL Read()
{
	LL x = 0,f = 1;char c = getchar();
	while(c > '9' || c < '0'){if(c == '-')f = -1;c = getchar();}
	while(c >= '0' && c <= '9'){x = (x*10) + (c^48);c = getchar();}
	return x * f;
}
TT void Put1(T x)
{
	if(x > 9) Put1(x/10);
	putchar(x%10^48);
}
TT void Put(T x,char c = -1)
{
	if(x < 0) putchar('-'),x = -x;
	Put1(x); if(c >= 0) putchar(c);
}
TT T Max(T x,T y){return x > y ? x : y;}
TT T Min(T x,T y){return x < y ? x : y;}
TT T Abs(T x){return x < 0 ? -x : x;}

int s[MAXN],tot,t[MAXN],bl[MAXN],pre[MAXN];
LL ans[MAXN];
struct Query{
	int l,r,ID;
	bool operator < (const Query &px)const{
		if(bl[l] ^ bl[px.l]) return bl[l] < bl[px.l];
		return r < px.r;
	}
}q[MAXN];
vector<Query> Q[MAXN];

int main()
{
//	freopen(".in","r",stdin);
//	freopen(".out","w",stdout);
	n = Read(); m = Read(); k = Read();
	if(k > 14){while(m --> 0) Put(0,'\n');return 0;}
	for(int i = 0;i < 16384;++ i) if(__builtin_popcount(i) == k) s[++tot] = i;
	B = ceil(sqrt(n));
	for(int i = 1;i <= n;++ i){
		pre[i] = t[a[i] = Read()]; bl[i] = (i-1)/B+1;
		for(int j = 1;j <= tot;++ j) ++t[a[i]^s[j]];
	}
	for(int i = 1;i <= m;++ i) q[i].l = Read(),q[i].r = Read(),q[i].ID = i;
	sort(q+1,q+m+1);
//	for(int i = 1;i <= m;++ i) printf("%d %d %d\n",q[i].l,q[i].r,q[i].ID);
	for(int i = 1,L = 1,R = 0;i <= m;++ i){
		if(R < q[i].r) Q[L-1].emplace_back(Query{R+1,q[i].r,-q[i].ID});
		while(R < q[i].r) ans[q[i].ID] += pre[++R];
		if(L > q[i].l) Q[R].emplace_back(Query{q[i].l,L-1,q[i].ID});
		while(L > q[i].l) ans[q[i].ID] -= pre[--L];
		if(L < q[i].l) Q[R].emplace_back(Query{L,q[i].l-1,-q[i].ID});
		while(L < q[i].l) ans[q[i].ID] += pre[L++];
		if(R > q[i].r) Q[L-1].emplace_back(Query{q[i].r+1,R,q[i].ID});
		while(R > q[i].r) ans[q[i].ID] -= pre[R--];
	}
	for(int i = 0;i < 16384;++ i) t[i] = 0;
	for(int i = 1;i <= n;++ i){
		for(int j = 1;j <= tot;++ j) ++t[a[i]^s[j]];
		for(auto &A : Q[i]){
			for(int j = A.l,val;j <= A.r;++ j){
				val = t[a[j]];
				if(j <= i && !k) --val;
				if(A.ID < 0) ans[-A.ID] -= val;
				else ans[A.ID] += val;
			}
		}
	}
	for(int i = 1;i <= m;++ i) ans[q[i].ID] += ans[q[i-1].ID];
	for(int i = 1;i <= m;++ i) Put(ans[i],'\n');
	return 0;
}
posted @ 2022-03-17 22:26  皮皮刘  阅读(32)  评论(0编辑  收藏  举报