题解 CF86D 【Powerful array】

CF86D Powerful array

传送门

蒟蒻刚学莫队,找题做,结果被块长卡了一个中午$RE$#$55$顺便拿了个最优解

思路

给出 $n,q,a_{1,2,...,n}$,每次询问给出$l$、$r$,$cnt_i$ 为 $l$、$r$ 区间中 $i$ 出现的次数,求 $\sum_icnt_i\times i$。

区间询问,考虑莫队维护。

莫队就是维护 $L,R$ ,对于每次询问跳到正确的区间处理的暴力算法,如果还不会右转P3901

此题与 $P3901$ 类似,也是拿一个 $cnt$ 数组存当前 $L,R$ 区间中 $i$ 的出现次数,考虑插入 $i$,由平方差公式得

$$ans={(cnt_i+1)}^2\times i-{cnt_i}^2\times i+ans=((cnt_i+cnt_i+1)\times (cnt_i-cnt_i+1))\times i+ans=(2\times cnt_i+1)\times i+ans$$

删除同理,转换符号即可。

接下来就是莫队基本操作了,$sz$ 作为块长取 $\frac{n}{\sqrt{\frac{3}{2}m}}+1$(因为#$55$中 $n<\sqrt{\frac{3}{2}m}$,导致出现 $sz$ 为 $0$ 的情况,得$+1$)最快。按照 $sz$ 进行奇偶排序,然后暴力跳 $L,R$ 就行了,具体见下代码内容。

$AC\;Code:$

#include<bits/stdc++.h>
using namespace std;
#define ll long long
namespace IO{//IO优化
    int len=0;
    char ibuf[(1<<20)+1],*iS,*iT,out[(1<<25)+1];
    #define gh() (iS==iT?iT=(iS=ibuf)+fread(ibuf,1,(1<<20)+1,stdin),(iS==iT?EOF:*iS++):*iS++)
//  #define gh() getchar()
    #define reg register
    inline int read(){
        reg char ch=gh();
        reg int x=0;
        while(ch<'0'||ch>'9') ch=gh();
        while(ch>='0'&&ch<='9') x=x*10+(ch^48),ch=gh();
        return x;
    }
    inline void write(ll x){
        if(x>9)write(x/10);
        out[len++]=x%10+48;
    }
}using namespace IO;
int n,m,k,curL=1,curR,sz,cnt[1000001],a[200001];//具体意义见上
ll g[200001],ans;//g_i表示第i次询问的答案
struct que{
    int id,l,r;
    friend bool operator<(const que &a,const que &b){
        return a.l/sz^b.l/sz?a.l<b.l:a.l/sz&1?a.r<b.r:a.r>b.r;//奇偶排序
    }
}ask[200001];//询问
inline void add(int p){//加
    cnt[a[p]]++,ans+=(2*cnt[a[p]]-1)*a[p];
}
inline void del(int p){//删
    cnt[a[p]]--,ans-=(2*cnt[a[p]]+1)*a[p];
}
int main(){
    n=read();
    m=read();
    sz=n/sqrt(m*2/3)+1;//块长
    for(int i=1;i<=n;i++){
        a[i]=read();
    }
    for(int i=1;i<=m;i++){
        int l=read(),r=read();
        ask[i]={i,l,r};
    }
    sort(ask+1,ask+m+1);//离散化
    for(int i=1;i<=m;i++){
        int L=ask[i].l,R=ask[i].r;
        while(curL>L) add(--curL);
        while(curR<R) add(++curR);
        while(curL<L) del(curL++);
        while(curR>R) del(curR--);
        g[ask[i].id]=ans;
    }
    for(int i=1;i<=m;i++){
        write(g[i]);
        out[len++]='\n';
    }
    fwrite(out,1,len,stdout);
    return 0;
}
/*
Time:18.14s
Memory:41.48MB
*/

那这就再见了 $qwq$~

posted @ 2020-12-10 22:14  ffffyc  阅读(13)  评论(0)    收藏  举报  来源