P2709 小B的询问(莫队入门)
题目链接:https://www.luogu.org/problemnew/show/P2709
题目大意:中文题目
具体思路:莫队入门题,按照离线的方式打的,对每一个区间进行分块和编号,如果在同一个块里面就按照右端点从小到大排列,如果不在同一个块里面就按照块的下标开始排序,这里的块是按照数列分块里面的方法来进行的,查询每个区间的值就可以了。
对于l,r指针的移动,当l<q[i].l的时候,我们需要将l指针往右移动,所以假设t为当前的颜色,ans为未移动的时候的值,首先去除掉原来的值的影响,ans-=t*t,然后再加上新的值的影响,ans+=(t+1)*(t+1),因为我们是先进行加减操作,所以这种情况下ans=-(t-1)*(t-1)+t*t=2*t-1.其他情况同理。
AC代码:
1 #include<iostream> 2 #include<stack> 3 #include<cstring> 4 #include<iomanip> 5 #include<stdio.h> 6 #include<cmath> 7 #include<algorithm> 8 #include<vector> 9 using namespace std; 10 # define ll long long 11 const int maxn = 2e5+100; 12 int a[maxn]; 13 struct node{ 14 int l,r,pos,id; 15 bool friend operator < (node t1,node t2){ 16 if(t1.pos==t2.pos)return t1.r<t2.r; 17 return t1.pos<t2.pos; 18 } 19 }q[maxn]; 20 int ans[maxn],vis[maxn]; 21 int main(){ 22 int n,m,k; 23 scanf("%d %d %d",&n,&m,&k); 24 int block=(int)sqrt(n); 25 for(int i=1;i<=n;i++){ 26 scanf("%d",&a[i]); 27 } 28 for(int i=1;i<=m;i++){ 29 scanf("%d %d",&q[i].l,&q[i].r); 30 q[i].pos=(q[i].l-1)/block+1; 31 q[i].id=i; 32 } 33 sort(q+1,q+m+1); 34 int tmp=0; 35 int l=1,r=0; 36 for(int i=1;i<=m;i++){ 37 while(l<q[i].l)vis[a[l]]--,tmp-=(2*vis[a[l]]+1),l++; 38 while(l>q[i].l)l--,vis[a[l]]++,tmp+=2*vis[a[l]]-1; 39 while(r<q[i].r)r++,vis[a[r]]++,tmp+=2*vis[a[r]]-1; 40 while(r>q[i].r)vis[a[r]]--,tmp-=2*vis[a[r]]+1,r--; 41 ans[q[i].id]=tmp; 42 } 43 for(int i=1;i<=m;i++){ 44 printf("%d\n",ans[i]); 45 } 46 return 0; 47 }