题意:给定数字的序列, 定义在区间中的distinct的数个数为k,值为w 那么这个数对于这个区间的贡献就是k^2*w
然后给出一堆的询问区间 问每个区间的贡献值之和是多少
解法:这一个题目的转移我用了比较笨的办法 就是每次减去之前的数对于当前区间的贡献 然后重算处理完当前的数之后的数的贡献 导致了效率不高 不过分块本来就是一种卡时间的算法了
这个要开输入挂 不开很难卡过去最后的那组 20w 20w
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<string.h>
using namespace std;
#define LL __int64
#define maxn 222222
#define sqr 480
int id[maxn],ll[maxn],rr[maxn];
LL cnt[maxn*10],a[maxn];
LL ans[maxn];
int cmp(int x,int y){
if(ll[x]/sqr==ll[y]/sqr){
return rr[x]<rr[y];
}else return ll[x]<ll[y];
}
int scan()
{
int res=0,ch;
while(!((ch= getchar())>='0'&&ch<='9')){
if(ch==EOF)return 1<<30;
}
res=ch-'0';
while((ch=getchar())>='0'&&ch<='9')
res=res*10+(ch-'0');
return res;
}
int n,m;
int main(){
scanf("%d%d",&n,&m);
for(int i=0;i<n;++i)scanf("%I64d",&a[i]);
for(int i=0;i<m;++i){
ll[i]=scan();rr[i]=scan();
--ll[i],--rr[i];
id[i]=i;
}
sort(id,id+m,cmp);
int nowl=0,nowr=-1;LL tot=0;
for(int i=0;i<m;++i){
int l=ll[id[i]],r=rr[id[i]];
while(nowr<r){
++nowr;
tot-=(cnt[a[nowr]]*cnt[a[nowr]]*a[nowr]);
cnt[a[nowr]]++;
tot+=(cnt[a[nowr]]*cnt[a[nowr]]*a[nowr]);
}
while(nowl>l){
--nowl;
tot-=(cnt[a[nowl]]*cnt[a[nowl]]*a[nowl]);
cnt[a[nowl]]++;
tot+=(cnt[a[nowl]]*cnt[a[nowl]]*a[nowl]);
}
while(nowr>r){
tot-=(cnt[a[nowr]]*cnt[a[nowr]]*a[nowr]);
cnt[a[nowr]]--;
tot+=(cnt[a[nowr]]*cnt[a[nowr]]*a[nowr]);
nowr--;
}
while(nowl<l){
tot-=(cnt[a[nowl]]*cnt[a[nowl]]*a[nowl]);
cnt[a[nowl]]--;
tot+=(cnt[a[nowl]]*cnt[a[nowl]]*a[nowl]);
nowl++;
}
ans[id[i]]=tot;
}
for(int i=0;i<m;++i)printf("%I64d\n",ans[i]);
return 0;
}