zoukankan      html  css  js  c++  java
  • 洛谷 P2709 小B的询问

    洛谷

    这题没人用分块吧?

    好像分块比较麻烦,但是我太弱了,不会莫队,就打了一个比较巧妙的分块。

    1.build函数。

    还是像普通分块一样的写,只是我们需要预处理两个数组。


    (f[i][j])表示从开始到第(i)块,颜色为(j)的颜色有多少个(前缀和)。

    这个东西很好处理。

    for (int i=1;i<=num;i++) {
        for (int j=1;j<=n;j++)
        f[i][a[j]]=f[i-1][a[j]];
        for (int j=l[i];j<=r[i];j++)
        f[i][a[j]]++;
    }
    

    (s[i][j])表示第(i)块,到第(j)块的贡献。

    换句话说,就是第i块到第j块之间的答案。也比较好处理。

    假设现在已经处理到了(s[i][j-1]),那么(s[i][j])中的颜色(k),每出现一次,就用一个(tmp[j])数组自加,

    最后假设(s[i][j-1])中颜色k出现次数为(x),那么$$x=f[j-1][k]-f[i-1][k]$$

    (s[i][j])中颜色k出现次数就是(x+tmp[k]).

    那么我们就让$$s[i][j]+=2*(x+tmp[k])+1$$

    为什么呢?例如(tmp[k]=1)时,$$(x+1){x+1}-x2=2×x+1$$

    还要注意一个问题,(tmp)数组要清零,当然不能单纯地使用(memset)(会超时),而是重复一次上面的循环,将它清零。

    for (int i=1;i<=num;i++)
        for (int j=i;j<=num;j++) {
            s[i][j]=s[i][j-1];
            for (int k=l[j];k<=r[j];k++) {
                int p=f[j-1][a[k]]-f[i-1][a[k]];
                s[i][j]+=2*(p+tmp[a[k]])+1;
                tmp[a[k]]++;
            }
            for (int k=l[j];k<=r[j];k++)
            tmp[a[k]]=0;
        }
    

    2.总的代码就是下面这样,很好理解:

    #include <bits/stdc++.h>
    using namespace std;
    
    const int N=50010,S=250;
    int n,m,q,a[N],s[S][S];
    int f[S][N],block,num;
    int belong[N],l[S],r[S],tmp[N];
    
    void build()
    {
        block=sqrt(n);
        num=n/block;
        if (n%block) num++;
        for (int i=1;i<=num;i++)
        l[i]=(i-1)*block+1,r[i]=i*block;
        r[num]=n;
        for (int i=1;i<=n;i++)
        belong[i]=(i-1)/block+1;
        for (int i=1;i<=num;i++) {
            for (int j=1;j<=n;j++)
            f[i][a[j]]=f[i-1][a[j]];
            for (int j=l[i];j<=r[i];j++)
            f[i][a[j]]++;
        }
        for (int i=1;i<=num;i++)
        for (int j=i;j<=num;j++) {
            s[i][j]=s[i][j-1];
            for (int k=l[j];k<=r[j];k++) {
                int p=f[j-1][a[k]]-f[i-1][a[k]];
                s[i][j]+=2*(p+tmp[a[k]])+1;
                tmp[a[k]]++;
            }
            for (int k=l[j];k<=r[j];k++)
            tmp[a[k]]=0;
        }
    }
    
    long long ask(int ls,int rs)
    {
        long long ans=0;
        if (belong[ls]==belong[rs]) {
            for (int i=ls;i<=rs;i++) {
                ans+=2*tmp[a[i]]+1;
                tmp[a[i]]++;
            }
            for (int i=ls;i<=rs;i++) tmp[a[i]]=0;
            return ans;
        }
        for (int i=ls;i<=r[belong[ls]];i++) {
            int p=f[belong[rs]-1][a[i]]-f[belong[ls]][a[i]];
            ans+=2*(p+tmp[a[i]])+1;
            tmp[a[i]]++;
        }
        for (int i=l[belong[rs]];i<=rs;i++) {
            int p=f[belong[rs]-1][a[i]]-f[belong[ls]][a[i]];
            ans+=2*(p+tmp[a[i]])+1;
            tmp[a[i]]++;
        }
        for (int i=ls;i<=r[belong[ls]];i++) tmp[a[i]]=0;
        for (int i=l[belong[rs]];i<=rs;i++) tmp[a[i]]=0;
        if (belong[ls]+1==belong[rs]) return ans;
        return ans+s[belong[ls]+1][belong[rs]-1];
    }
    
    int main()
    {
        ios::sync_with_stdio(0);
        cin>>n>>m>>q;
        for (int i=1;i<=n;i++)
        cin>>a[i];
        build();
        while (m--) {
            int ls,rs;
            cin>>ls>>rs;
            cout<<ask(ls,rs)<<endl;
        }
        return 0;
    }
    
  • 相关阅读:
    第一章:Android系统的编译和移植实例读书笔记
    第二章:Android系统与嵌入式开发读书笔记
    第三章:Android移植平台工具介绍读书笔记
    第十章 嵌入式Linux的调试技术
    第九章 硬件抽象层:HAL
    第八章 让开发板发出声音:蜂鸣器驱动
    第七章 LED将为我闪烁:控制发光二极管
    第六章 第一个Linux驱动程序:统计单词个数
    第五章 搭建S3C6410开发板的测试环境
    第四章 源代码的下载和编译
  • 原文地址:https://www.cnblogs.com/fushao2yyj/p/9512574.html
Copyright © 2011-2022 走看看