Codeforces 86D Powerful array (莫队算法)

题目链接 Powerful array

给你n个数,m次询问,Ks为区间内s的数目,求区间[L,R]之间所有Ks*Ks*s的和。

$1<=n,m<=200000,   1<=s<=10^{6}$

考虑莫队算法

把区间排序,然后让l和r分别询问即可。

根据排序的方式,l指针和r指针移动次数和大概是$nsqrt{n}$ 级别的。

#include <bits/stdc++.h>

using namespace std;

#define rep(i, a, b)	for (int i(a); i <= (b); ++i)
#define dec(i, a, b)	for (int i(a); i >= (b); --i)

typedef long long LL;

const int N = 2e5 + 10;
const int M = 1e6 + 10;

int belong[N];

struct query{
	int l, r;
	int id;
	void scan(){ scanf("%d%d", &l, &r); }
	friend bool operator < (const query &a, const query &b){
		return belong[a.l] == belong[b.l] ? a.r < b.r : 
			belong[a.l] < belong[b.l];
	}
} q[N];

int n, m;
int a[N], c[M];
int BS, l, r;
LL  ret[N], ans;


int main(){

	scanf("%d%d", &n, &m);
	rep(i, 1, n) scanf("%d", a + i);

	BS = sqrt(n);
	rep(i, 1, n) belong[i] = (i - 1) / BS + 1;	
	rep(i, 1, m){
		q[i].scan();
		q[i].id = i;
	}
	

	sort(q + 1, q + m + 1);
	l = 0; r = 0; ans = 0;
	
	rep(i, 1, m){
		while (l > q[i].l){
			--l;
			ans += (LL)(2 * c[a[l]] + 1) * a[l];
			++c[a[l]];
		}

		while (r < q[i].r){
			++r;
			ans += (LL)(2 * c[a[r]] + 1) * a[r];
			++c[a[r]];
		}

		while (l < q[i].l){
			--c[a[l]];
			ans -= (LL)(2 * c[a[l]] + 1) * a[l];
			++l;
		}

		while (r > q[i].r){
			--c[a[r]];
			ans -= (LL)(2 * c[a[r]] + 1) * a[r];
			--r;
		}

		ret[q[i].id] = ans;
	}


	rep(i, 1, m) printf("%lld
", ret[i]);
	return 0;
}
原文地址:https://www.cnblogs.com/cxhscst2/p/7503622.html