[莫队] 洛谷 P2709 小B的询问

题目描述

小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

 

题解

  • 题目大意:区间[L..R],求Sigma(c(i)^2),c[i]为i数字在区间出现的次数
  • 这题显然就是小Z的袜子的弱化版,具体解法就可看链接里的博客
  • 其实就是将小Z的袜子去掉分母

代码

 1 #include <cstdio>
 2 #include <iostream>
 3 #include <cstring>
 4 #include <algorithm>
 5 #include <cmath>
 6 #define ll long long
 7 #define N 50010
 8 #define sqr(x) (x)*(x)
 9 using namespace std;
10 struct edge { int l,r,d; ll a; }e[N];
11 int n,m,num,bel[N],sum[N],a[N],k;
12 ll ans;
13 bool cmp(edge a,edge b) { return bel[a.l]==bel[b.l]?a.r<b.r:a.l<b.l; }
14 bool cmp1(edge a,edge b) { return a.d<b.d; }
15 void work(int x,int k) { ans-=sqr(sum[a[x]]),sum[a[x]]+=k,ans+=sqr(sum[a[x]]); }
16 int main()
17 {
18     scanf("%d%d%d",&n,&m,&k),num=sqrt(n);
19     for (int i=1;i<=n;i++) scanf("%d",&a[i]),bel[i]=i/num+1;
20     for (int i=1;i<=m;i++) scanf("%d%d",&e[i].l,&e[i].r),e[i].d=i;
21     sort(e+1,e+m+1,cmp);
22     int l=1,r=0;
23     for (int i=1;i<=m;i++)
24     {
25         while (l<e[i].l) work(l,-1),l++;
26         while (l>e[i].l) work(l-1,1),l--;
27         while (r<e[i].r) work(r+1,1),r++;
28         while (r>e[i].r) work(r,-1),r--;
29         e[i].a=ans;
30     }
31     sort(e+1,e+m+1,cmp1);
32     for (int i=1;i<=m;i++) printf("%lld\n",e[i].a);
33 }

 

posted @ 2019-01-22 21:53  BEYang_Z  阅读(180)  评论(0编辑  收藏  举报