ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

洛谷 P2801 教主的魔法

2020-01-29 12:53:07  阅读:305  来源: 互联网

标签:洛谷 int P2801 魔法 查询 rb ans lb 排序


题目链接

话说分块的坑点好多啊,一不小心就会越界什么的真是麻烦QWQ

0x00 思路

面对区间修改区间查询,我们有两种基本思路:线段树和分块

可是很明显我们查询的东西不满足区间加法的性质,而且每次查询的标准在变,我们考虑直接上分块暴力维护

0x01 分块思路

定义块大小为\(size = sqrt(n)\)

查询/修改的区间为\([l,r]\),查询/修改的值为\(v\)

\(l\)所在的块为\(lb\),\(r\)所在的块为\(rb\)

查询:

  1. 对于完整的块,我们将其中的元素排序,二分查找最小的符合条件的数的位置,作差即可计算贡献

  2. 对于不完整的块,我们直接枚举每一个数,计算贡献

修改:

  1. 对于完整的块,我们用\(block\)数组打标记,表示整个块全部加上\(v\),就像线段树的懒标记一样,查找的时候刚好可以用上

  2. 对于不完整的块,我们直接枚举每个数,加上\(v\),然后重新将块内的元素排序

细节:

  1. 我们开两个数组,\(a\)和\(tmp\),\(a\)数组存储的是原数组,\(tmp\)存储的是排序后的数组,排序我们是每次只排序一块内的数

  2. 每次要重排序块内的数时,可以从\(a\)中复制一份到\(tmp\)中,然后排序

  3. 各种下标要注意,时刻保证块的右端点不能超过\(n\)

  4. 对于\(lb = rb\)的情况,要特判

0x02 Code


#include<bits/stdc++.h>
using namespace std;
#define N 1000010
#define M 1010
int read(){
    int x=0; char c=getchar(); int flag=1;
    while(!isdigit(c)) { if(c=='-') flag=-1; c=getchar(); }
    while(isdigit(c)) { x=((x+(x<<2))<<1)+(c^48); c=getchar(); }
    return x*flag;
}
int n,m,size,belong[N];
long long a[N],tmp[N],block[M];
signed main(){
    n = read(),m = read(),size = sqrt(n);
    for(int i = 1;i <= n;i ++) a[i] = read(),belong[i] = (i - 1) / size + 1,tmp[i] = a[i];
    for(int i = 1;(i - 1) * size + 1 <= n;i ++){
        int l = (i - 1) * size + 1,r = min(n,i * size);
        sort(tmp + l,tmp + r + 1);
    }
    while(m --){
        char opt;
        int l,r,v;
        scanf(" %c %d %d %d",&opt,&l,&r,&v);
        if(opt == 'A'){
            int lb = belong[l],rb = belong[r],ans = 0;
            if(lb == rb){
                for(int i = l;i <= r;i ++) if(a[i] + block[lb] >= v) ++ ans;
                printf("%d\n",ans);
                continue;
            }
            for(int i = lb + 1;i <= rb - 1;i ++){
                int l = (i - 1) * size + 1,r = i * size,ps = r + 1;
                while(l <= r){
                    int mid = ((l + r) >> 1);
                    if(tmp[mid] + block[i] >= v) { ps = mid; r = mid - 1; }
                    else l = mid + 1;
                }
                ans += i * size - ps + 1;
            }
            for(int i = l;i <= lb * size;i ++) if(a[i] + block[lb] >= v) ++ ans;
            for(int i = (rb - 1) * size + 1;i <= r;i ++) if(a[i] + block[rb] >= v) ++ ans;
            printf("%d\n",ans); 
        }
        if(opt == 'M'){
            int lb = belong[l],rb = belong[r];
            if(lb == rb){
                for(int i = l;i <= r;i ++) a[i] += v;
                for(int i = (lb - 1) * size + 1;i <= min(lb * size,n);i ++) tmp[i] = a[i];
                sort(tmp + (lb - 1) * size + 1,tmp + min(lb * size,n) + 1);
                continue;
            }
            for (int i = lb + 1;i <= rb - 1;i ++) block[i] += v;
            
            for (int i = l;i <= lb * size;i ++) a[i] += v;
            for (int i = (lb - 1) * size + 1;i <= lb * size;i ++) tmp[i] = a[i];
            sort(tmp + (lb - 1) * size + 1,tmp + lb * size + 1);
            
            for (int i = (rb - 1) * size + 1;i <= r;i ++) a[i] += v;
            for (int i = (rb - 1) * size + 1;i <= min(rb * size,n);i ++) tmp[i] = a[i];
            sort(tmp + (rb - 1) * size + 1,tmp + min(rb * size,n) + 1);
        }
    }
    return 0;
}

标签:洛谷,int,P2801,魔法,查询,rb,ans,lb,排序
来源: https://www.cnblogs.com/zzhzzh123/p/12240038.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有