洛谷 P2709 小B的询问 【莫队】

洛谷 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 的移动没变,变的是更新状态这一部分:

1 void revise(int x,int w)
2 {
3     if (w>0) sum+=2*num[a[x]]+1;
4     if (w<0) sum-=2*num[a[x]]-1;
5     num[a[x]]+=w;
6 }

设 i 在此段中的数量为 x ,若是新增一个 i ,则根据公式可推出:ans+=(x+1)^2-x^2 ==> 2x+1

若是减少一个 i ,根据公式可推出:ans-=x^2-(x-1)^2 ==> 2x-1

还要注意一个非常重要的细节(所有的莫队题目都要注意!!!我在这个地方卡了超长时间,终于调出来了), 一开始的指针 l 和 r 初始化要注意, l=1, r=0

这个要切记,不然就会WA(因为 l=0 的话就会把下标为 -1 的这个点算上去)。

废话不多说,上代码:

 1 #include<bits/stdc++.h>
 2 #define ll long long 
 3 using namespace std;
 4 const int N=50005;
 5 ll n,m,k,a[N],sum,num[N],block,belong[N],ans[N];
 6 struct node{
 7     int l,r,id;
 8 }q[N];
 9 inline ll read()
10 {
11     ll x=0,f=1; char ch=getchar();
12     while (!isdigit(ch))
13       f=(ch=='-')?-f:f,ch=getchar();
14     while (isdigit(ch))
15       x=(x<<3)+(x<<1)+ch-'0',ch=getchar();
16     return x*f;
17 }
18 bool cmp(node a,node b)
19 {
20     return belong[a.l]==belong[b.l]?a.r<b.r:belong[a.l]<belong[b.l];
21 }
22 inline ll sqr(int x)
23 {
24     return x*x;
25 }
26 void revise(int x,int w)
27 {
28     ///*
29     if (w>0) sum+=2*num[a[x]]+1;
30     if (w<0) sum-=2*num[a[x]]-1;
31     num[a[x]]+=w;
32     //*/
33     /*
34     num[a[x]]+=w;
35     if (w>0) sum+=2*num[a[x]]-1;
36     if (w<0) sum-=2*num[a[x]]+1;
37     */
38     /*if (w>0) sum+=num[a[x]]<<1|1,num[a[x]]+=w;
39     if (w<0) num[a[x]]+=w,sum-=num[a[x]]<<1|1;
40     //num[a[x]]+=w; 
41     */
42     
43 }
44 int main()
45 {
46     n=read(),m=read(),k=read();
47     block=sqrt(n);
48     for (int i=1; i<=n; i++)
49     {
50         a[i]=read(); belong[i]=i/block+1;
51     }
52     for (int i=1; i<=m; i++)
53     {
54         q[i].l=read(),q[i].r=read(),q[i].id=i;
55     }
56     sort(q+1,q+1+m,cmp);
57     int zl=1,zr=0; sum=0;
58     memset(num,0,sizeof(num));
59     for (int i=1; i<=m; i++)
60     {
61         while (zl<q[i].l) revise(zl,-1),zl++;
62         while (zl>q[i].l) revise(zl-1,1),zl--;
63         while (zr<q[i].r) revise(zr+1,1),zr++;
64         while (zr>q[i].r) revise(zr,-1),zr--;
65         ans[q[i].id]=sum;
66     }
67     for (int i=1; i<=m; i++)
68     {
69         printf("%lld\n",ans[i]);
70     }
71     return 0;
72 }
View Code

加油加油加油!!! fighting fighting fighting !!!

猜你喜欢

转载自www.cnblogs.com/Frank-King/p/9168944.html