BZOJ 3781 小B的询问 莫队算法

题目大意:一共有M个询问,每个询问给定一个区间[L..R],求Sigma(c(i)^2)的值,其中i的值从1到K,其中c(i)表示数字i在[L..R]中的重复次数。


思路:莫队走起。


CODE:

#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define MAX 50010
using namespace std;

int belong[MAX],block_size;

struct Ask{
	int x,y,id;
	
	bool operator <(const Ask &a)const {
		if(belong[x] == belong[a.x])	return y <= a.y;
		return belong[x] < belong[a.x];
	}
	void Read(int p) {
		scanf("%d%d",&x,&y);
		id = p;
		belong[p] = p / block_size;
	}
}ask[MAX];

int cnt,asks;
int src[MAX];

int v[MAX],now;
int ans[MAX];

int main()
{
	cin >> cnt >> asks;
	scanf("%*d");
	block_size = sqrt(cnt);
	for(int i = 1; i <= cnt; ++i)
		scanf("%d",&src[i]);
	for(int i = 1; i <= asks; ++i)
		ask[i].Read(i);
	sort(ask + 1,ask + asks + 1);
	int l = 1,r = 0;
	for(int temp,i = 1; i <= asks; ++i) {
		while(r < ask[i].y) {
			temp = src[++r];
			now -= v[temp] * v[temp];
			++v[temp];
			now += v[temp] * v[temp];
		}
		while(l > ask[i].x) {
			temp = src[--l];
			now -= v[temp] * v[temp];
			++v[temp];
			now += v[temp] * v[temp];
		}
		while(l < ask[i].x) {
			temp = src[l++];
			now -= v[temp] * v[temp];
			--v[temp];
			now += v[temp] * v[temp];
		}
		while(r > ask[i].y) {
			temp = src[r--];
			now -= v[temp] * v[temp];
			--v[temp];
			now += v[temp] * v[temp];
		}
		ans[ask[i].id] = now;
	}
	for(int i = 1; i <= asks; ++i)
		printf("%d\n",ans[i]);
	return 0;
}


你可能感兴趣的:(bzoj,莫队算法)