洛谷P2709 小B的询问

这个题可以用莫队的方法来解决,通过创建数组来保存数的出现个数,再在每次添加或删除的时候保存一个答案,这样就能做出这道题。

#include<stdio.h>
#include<math.h>
struct node{
    int l,r,id;
}a[100001],pxr[100001];
int n,sqn,m,js[100001],b[100001],ans,cnt[100001],nowl,nowr;
int kx;
int cmp(struct node a1,struct node a2){return(a1.l/sqn)==(a2.l/sqn)?a1.r<a2.r:a1.l<a2.l;}
int px(int l,int r){
    if(l==r)return 0;
    int k,s,mid,p;
    mid=(l+r)>>1;
    k=l;s=mid+1;p=l;
    px(l,mid);px(mid+1,r);
    while(k<=mid&&s<=r)if(cmp(a[k],a[s]))pxr[p++]=a[k++];else pxr[p++]=a[s++];
    while(k<=mid)pxr[p++]=a[k++];
    while(s<=r)pxr[p++]=a[s++];
    for(p=l;p<=r;p++)a[p]=pxr[p];
    return 0;
}
void add(int x){
    ans=ans-js[b[x]]*js[b[x]]+(js[b[x]]+1)*(js[b[x]]+1);
    ++js[b[x]];
}
void del(int x){
    ans=ans-js[b[x]]*js[b[x]]+(js[b[x]]-1)*(js[b[x]]-1);
    --js[b[x]];
}
int read(){
    int res=0,zf=1;
    char ch;
    while((ch=getchar())<48||ch>57)if(ch=='-')zf=!zf;
    res=(ch^48);
    while((ch=getchar())>=48&&ch<=57)res=(res<<3)+(res<<1)+(ch^48);
    return zf?res:(-res);
}
int main(){
    n=read();
    m=read();
    kx=read();
    sqn=sqrt(n);
    for(int i=1;i<=n;i++)b[i]=read();
    for(int i=1;i<=m;i++){a[i].l=read();a[i].r=read();a[i].id=i;}
    px(1,m);
    ans=-1;
    for(int i=1;i<=m;i++){
        while(nowr<a[i].r)add(++nowr);
        while(nowr>a[i].r)del(nowr--);

        while(nowl<a[i].l)del(nowl++);
        while(nowl>a[i].l)add(--nowl);
        cnt[a[i].id]=ans;
        
    }
    for(int i=1;i<=m;i++)printf("%d\n",cnt[i]);
    return 0;
}

 

posted @ 2020-08-30 21:47  __int128  阅读(140)  评论(0编辑  收藏  举报