1. 程式人生 > >洛谷 P2709 小B的詢問 【莫隊】

洛谷 P2709 小B的詢問 【莫隊】

加油 ide close turn sample getch pac ID sed

洛谷 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 !!!

洛谷 P2709 小B的詢問 【莫隊】