小B的询问
题目描述
小B有一个序列,包含N个1~K之间的整数。他一共有M个询问,每个询问给定一个区间[L..R],求Sigma(c(i)^2)的值,其中i的值从1到K,其中c(i)表示数字i在[L..R]中的重复次数。小B请你帮助他回答询问。
对于全部的数据,1<=N、M、K<=50000
题解
分块可以做,考虑怎么当端点移动时,怎么维护答案。
当区间扩张到i,只对c(i)有影响,所以只有c(i)的值变成(c(i)+1),那么答案就很好维护了,增加了2*c(i)+1
当区间缩短,同理只有c(i)变成(c(i)-1),所以减去(2*c(i)-1)
只要是记录一下莫队模板
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include<bits/stdc++.h> using namespace std; const int maxn=50005; int n,m,k,ret; int a[maxn],cnt[maxn]; int size,pos[maxn]; int ans[maxn]; struct question{ int l,r,id; }q[maxn]; template<class T>inline void read(T &x){ x=0;char ch=getchar(); while(!isdigit(ch)) ch=getchar(); while(isdigit(ch)) {x=(x<<1)+(x<<3)+(ch^48);ch=getchar();} } bool cmp(question a,question b){ if(pos[a.l]==pos[b.l]) return a.r<b.r; return pos[a.l]<pos[b.l]; } void add(int x){ ret+=2*cnt[a[x]]+1; cnt[a[x]]++; } void del(int x){ ret-=2*cnt[a[x]]-1; cnt[a[x]]--; } int main(){ read(n);read(m);read(k); size=sqrt(n+0.5); for(int i=1;i<=n;i++){read(a[i]);pos[i]=(i-1)/size+1;} for(int i=1;i<=m;i++){read(q[i].l);read(q[i].r);q[i].id=i;} sort(q+1,q+m+1,cmp); int nowl=1,nowr=0; for(int i=1;i<=m;i++){ while(nowl>q[i].l) add(--nowl); while(nowr<q[i].r) add(++nowr); while(nowl<q[i].l) del(nowl++); while(nowr>q[i].r) del(nowr--); ans[q[i].id]=ret; } for(int i=1;i<=m;i++) printf("%d\n",ans[i]); }
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步