• 【洛谷2709】小B的询问(莫队模板题)


    点此看题面

    大致题意: 有一个长度为(N)的序列,每个数字在(1sim K)之间,有(M)个询问,每个询问给你一个区间,让你求出(sum_{i=1}^K c(i)^2),其中(c(i))表示数字(i)在该区间内的出现次数。

    莫队算法

    显然,这题可以用莫队算法来做,而这题本身就是莫队算法的一道模板题。

    代码

    #include<bits/stdc++.h>
    #define N 50000
    #define M 50000
    using namespace std;
    int n,Q,k,a[N+5],pos[N+5],cnt[N+5],ans[M+5];
    struct Query
    {
        int l,r,pos;
    }q[M+5];
    inline char tc()
    {
        static char ff[100000],*A=ff,*B=ff;
        return A==B&&(B=(A=ff)+fread(ff,1,100000,stdin),A==B)?EOF:*A++;
    }
    inline void read(int &x)
    {
        x=0;char ch;
        while(!isdigit(ch=tc()));
        while(x=(x<<3)+(x<<1)+ch-'0',isdigit(ch=tc()));
    }
    inline void write(int x)
    {
        if(x>9) write(x/10);
        putchar(x%10+'0');
    }
    bool cmp(Query x,Query y)
    {
        return pos[x.l]<pos[y.l]||(pos[x.l]==pos[y.l]&&(pos[x.l]&1?x.r<y.r:x.r>y.r));
    }
    int main()
    {
        register int i;
        read(n),read(Q),read(k);
        for(i=1;i<=n;++i) read(a[i]),pos[i]=(i-1)/sqrt(n)+1;//边读入,边将序列分块
        for(i=1;i<=Q;++i) read(q[i].l),read(q[i].r),q[i].pos=i;//存储下来每一个询问
        sort(q+1,q+Q+1,cmp);//将询问以l所在的块为第一关键字,r的值为第二关键字sort一遍
        int L=q[1].l,R=q[1].r;//将L指针和R指针预处理为指向第一个询问的l和r
        for(i=q[1].l;i<=q[1].r;++i)//暴力求解第一个询问
        	ans[q[1].pos]-=cnt[a[i]]*cnt[a[i]],++cnt[a[i]],ans[q[1].pos]+=cnt[a[i]]*cnt[a[i]];
        for(i=2;i<=Q;++i)//对每一个询问依次求解
        {
        	ans[q[i].pos]=ans[q[i-1].pos];
            while(L<q[i].l) ans[q[i].pos]-=cnt[a[L]]*cnt[a[L]],--cnt[a[L]],ans[q[i].pos]+=cnt[a[L]]*cnt[a[L]],++L;//若L小于当前询问的l,则更新ans,并将L加1
            while(L>q[i].l) --L,ans[q[i].pos]-=cnt[a[L]]*cnt[a[L]],++cnt[a[L]],ans[q[i].pos]+=cnt[a[L]]*cnt[a[L]];//若L大于当前询问的l,则将L减1,并更新ans(注意,这里改变L值和更新ans的顺序与上一个操作不同)
            while(R>q[i].r) ans[q[i].pos]-=cnt[a[R]]*cnt[a[R]],--cnt[a[R]],ans[q[i].pos]+=cnt[a[R]]*cnt[a[R]],--R;//类似于上面的操作
            while(R<q[i].r) ++R,ans[q[i].pos]-=cnt[a[R]]*cnt[a[R]],++cnt[a[R]],ans[q[i].pos]+=cnt[a[R]]*cnt[a[R]];//类似于上面的操作
        }
        for(i=1;i<=Q;++i) write(ans[i]),putchar('
    ');//对每一个答案按照读入顺序输出
        return 0;
    }
    
  • 相关阅读:
    蚂蚁和木杆问题
    计算二进制中1的个数(转)
    strlen源码剖析(转)
    bashrc
    smb.conf配置文件(Centos)
    配置VNC+PuTTY+SSH Tunnel访问Linux
    标题: BASH最常见的激活模式
    KMP算法
    字符串中单词逆序
    Java中堆内存和栈内存详解
  • 原文地址:https://www.cnblogs.com/chenxiaoran666/p/Luogu2709.html
Copyright © 2020-2023  润新知