• 【bzoj3343】 教主的魔法(分块入门)


    题意:一个含n个数的区间(n<=1000000),k次操作,两种操作:

              M a,b,c  将区间[a,b]中的每一个数加c;

              A a,b,c  查询区间[a,b]中大于c的数的个数;

    思路:将区间分为sqrt(n)块,对每块进行排序;

              对于查询区间,两端的块外区间暴力处理,中间的块内区间特殊处理(二分);

             借助add标记,实现优化;

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<cmath>
    using namespace std;
    int add[5000100],num[5000100];
    int pos[5000100],b[5000100];
    int t,n,m,block,temp;
    char str[5050];
    void reset(int x) //区间排序
    {
        int l=(x-1)*block+1;
        int r=min(x*block,n);
        for(int i=l;i<=r;i++)
        {
            b[i]=num[i];
        }
        sort(b+l,b+r+1);
    }
    int find(int x,int v) //块内二分查询
    {
        int l=(x-1)*block+1;
        int r=min(x*block,n);
        int last=r;
        while(l<=r)
        {
            int mid=(l+r)/2;
            if(b[mid]<v) l=mid+1;
            else r=mid-1;
        }
        return last-l+1;
    }
    void update(int x,int y,int v)
    {
        if(pos[x]==pos[y])
        {
            for(int i=x;i<=y;i++) num[i]+=v;
        }
        else
        {
            for(int i=x;i<=pos[x]*block;i++) num[i]+=v;
            for(int i=(pos[y]-1)*block+1;i<=y;i++) num[i]+=v;
        }
        reset(pos[x]);reset(pos[y]);//注意
        for(int i=pos[x]+1;i<pos[y];i++) add[i]+=v;
    }
    int query(int x,int y,int v)
    {
        int sum=0;
        if(pos[x]==pos[y])
        {
            for(int i=x;i<=y;i++)
                if(num[i]+add[pos[i]]>=v) sum++;
        }
        else
        {
            for(int i=x;i<=pos[x]*block;i++)
                if(num[i]+add[pos[i]]>=v) sum++;
            for(int i=(pos[y]-1)*block+1;i<=y;i++)
                if(num[i]+add[pos[i]]>=v) sum++;
        }
        for(int i=pos[x]+1;i<pos[y];i++)
            sum+=find(i,v-add[i]);
        return sum;
    }
    int main()
    {
        int i,j,k,x,y,z;
        while(scanf("%d%d",&n,&m)!=EOF)
        {
            block=(int)sqrt(n);
            for(i=1;i<=n;i++)
            {
                scanf("%d",&num[i]);
                pos[i]=(i-1)/block+1;
                b[i]=num[i];//不要忽略
            }
            if(n%block) temp=n/block+1;
            else temp=n/block;
            for(i=1;i<=temp;i++) reset(i);
            for(i=1;i<=m;i++)
            {
                scanf("%s%d%d%d",str,&x,&y,&z);
                if(str[0]=='M') update(x,y,z);
                else printf("%d
    ",query(x,y,z));
            }
        }
        return 0;
    }
  • 相关阅读:
    进度条简单实现
    bootstrap学习(二)-----Modal模态框
    PL/SQL Developer登入时候报ORA-12638: 身份证明检索失败的解决办法
    pdf.js在IIS中配置使用笔记
    JSON数据查询方法
    Visual Studio 2013 错误提示“未找到与约束匹配”的修正
    WebStorm 11激活方法
    Xamarin开发Android笔记:使用ZXing进行连续扫描
    Xamarin开发IOS笔记:切换输入法时输入框被遮住
    Xamarin开发Android笔记:拍照或相册选取图片角度问题
  • 原文地址:https://www.cnblogs.com/dashuzhilin/p/4657091.html
Copyright © 2020-2023  润新知