CF86D Powerful array

题面翻译

  • 给定长度为 \(n\) 的序列 \(a\),有 \(q\) 次询问,每次询问给出两个数 \(l,r\)
  • 对于每次询问,设 \(cnt_i\) 表示 \(i\)\(a_l,a_{l+1},\cdots,a_r\) 出现的次数,您需要求出 \(\displaystyle\sum_i cnt_i^2\cdot i\)
  • \(1\le n,q\le 2\times 10^5\)\(1\le a_i\le 10^6\)\(1\le l\le r\le n\)

样例 #1

样例输入 #1

3 2
1 2 1
1 2
1 3

样例输出 #1

3
6

样例 #2

样例输入 #2

8 3
1 1 2 2 1 3 1 1
2 7
1 6
2 7

样例输出 #2

20
20
20

分析

发现已知当前区间 \([l,r]\) 可以转移到区间 \([l-1,r],[l+1,r],[l,r-1],[l,r+1]\),再维护一个区间出现次数的信息即可莫队。

#include<bits/stdc++.h>
#define int long long
using namespace std;
inline int read(){
	int x=0,f=1;
	char c=getchar();
	while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
	while(c>='0'&&c<='9')x=(x<<1)+(x<<3)+(c&15),c=getchar();
	return x*f;
}
int n,m,bl,a[200005],cnt[1000005],pos[200005],ans[200005],res;
struct node{
	int l,r,id;
}q[200005];
bool cmp(node x,node y){return pos[x.l]^pos[y.l]?pos[x.l]<pos[y.l]:x.r<y.r;}
void add(int x){
	res-=cnt[a[x]]*cnt[a[x]]*a[x];
	++cnt[a[x]];
	res+=cnt[a[x]]*cnt[a[x]]*a[x];
}
void del(int x){
	res-=cnt[a[x]]*cnt[a[x]]*a[x];
	--cnt[a[x]];
	res+=cnt[a[x]]*cnt[a[x]]*a[x];
}
signed main(){
	n=read(),m=read();bl=pow(n,0.55);
	for(int i=1;i<=n;i++)a[i]=read(),pos[i]=(i-1)/bl+1;
	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,cmp);
	for(int i=1,l=1,r=0;i<=m;i++){
		while(q[i].l<l)add(--l);
		while(q[i].l>l)del(l++);
		while(q[i].r>r)add(++r);
		while(q[i].r<r)del(r--);
		ans[q[i].id]=res;
	}
	for(int i=1;i<=m;i++)printf("%lld\n",ans[i]);
	return 0;
}
posted @ 2023-06-24 14:16  alex_liu09  阅读(7)  评论(0)    收藏  举报