题目描述
小B有一个序列,包含N个1~K之间的整数。他一共有M个询问,每个询问给定一个区间[L..R],求Sigma(c(i)^2)的值,其中i的值从1到K,其中c(i)表示数字i在[L..R]中的重复次数。小B请你帮助他回答询问。
输入格式
第一行,三个整数N、M、K。
第二行,N个整数,表示小B的序列。
接下来的M行,每行两个整数L、R。
输出格式
M行,每行一个整数,其中第i行的整数表示第i个询问的答案。
输入输出样例
输入 #1
6 4 3 1 3 2 1 1 3 1 4 2 6 3 5 5 6
输出 #1
6 9 5 2
说明/提示
对于全部的数据,1<=N、M、K<=50000
很显然我们移动的越少
跑得就越快是吧?
所以我们把询问抽象成点
就是要求曼哈顿距离的最小生成树。
#include<iostream> #include<cstring> #include<string> #include<algorithm> #include<cmath> #include<cstdio> #define MAXN 50001 using namespace std; int n,m,k,qwq,bz; int a[MAXN],cnt[MAXN],ans[MAXN]; struct node{ int l,r,num; }ask[MAXN]; inline int read(){ int x=0;bool f=0;char c=getchar(); while(c<'0'||c>'9'){if(c=='-')f=!f;c=getchar();} while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();} return f?-x:x; } inline bool cmp(node x,node y){ return (x.num/bz==y.num/bz)?x.r<y.r:x.l<y.l; } inline void remove(int pos){ qwq-=cnt[a[pos]]*cnt[a[pos]],--cnt[a[pos]]; qwq+=cnt[a[pos]]*cnt[a[pos]]; } inline void add(int pos){ qwq-=cnt[a[pos]]*cnt[a[pos]],++cnt[a[pos]]; qwq+=cnt[a[pos]]*cnt[a[pos]]; } int main(){ n=read(),m=read(),k=read(); bz=sqrt(n); for(register int i=1;i<=n;++i) a[i]=read(); for(register int i=1;i<=m;++i){ ask[i].num=i; ask[i].l=read(),ask[i].r=read(); } sort(ask+1,ask+m+1,cmp); int nl=1,nr=0; for(register int i=1;i<=m;++i){ int L=ask[i].l,R=ask[i].r; while(nl<L) remove(nl++); while(nl>L) add(--nl); while(nr<R) add(++nr); while(nr>R) remove(nr--); ans[ask[i].num]=qwq; } for(register int i=1;i<=m;++i){ printf("%d ",ans[i]); } return 0; }