zoukankan      html  css  js  c++  java
  • 【分块】教主的魔法 @洛谷P2801/upcexam3138

    时间限制: 1 Sec 内存限制: 128 MB
    题目描述
    教主最近学会了一种神奇的魔法,能够使人长高。于是他准备演示给XMYZ信息组每个英雄看。于是N个英雄们又一次聚集在了一起,这次他们排成了一列,被编号为1、2、……、N。
    每个人的身高一开始都是不超过1000的正整数。教主的魔法每次可以把闭区间[L, R](1≤L≤R≤N)内的英雄的身高全部加上一个整数W。(虽然L=R时并不符合区间的书写规范,但我们可以认为是单独增加第L(R)个英雄的身高)
    CYZ、光哥和ZJQ等人不信教主的邪,于是他们有时候会问WD闭区间 [L, R] 内有多少英雄身高大于等于C,以验证教主的魔法是否真的有效。
    WD巨懒,于是他把这个回答的任务交给了你。
    输入
    第1行为两个整数N、Q。Q为问题数与教主的施法数总和。
    第2行有N个正整数,第i个数代表第i个英雄的身高。
    第3到第Q+2行每行有一个操作:
    (1)若第一个字母为“M”,则紧接着有三个数字L、R、W。表示对闭区间 [L, R] 内所有英雄的身高加上W。
    (2)若第一个字母为“A”,则紧接着有三个数字L、R、C。询问闭区间 [L, R] 内有多少英雄的身高大于等于C。
    输出
    对每个“A”询问输出一行,仅含一个整数,表示闭区间 [L, R] 内身高大于等于C的英雄数。
    样例输入
    5 3
    1 2 3 4 5
    A 1 5 4
    M 3 5 1
    A 1 5 4
    样例输出
    2
    3
    提示
    原先5个英雄身高为1、2、3、4、5,此时[1, 5]间有2个英雄的身高大于等于4。教主施法后变为1、2、4、5、6,此时[1, 5]间有3个英雄的身高大于等于4。
    对30%的数据,N≤1000,Q≤1000。
    对100%的数据,N≤1000000,Q≤3000,1≤W≤1000,1≤C≤1,000,000,000

    第一次写分块题
    将数据分成sqrt(n)块,对每个块分别排序。
    对于修改操作,区间内完整的块修改其add数组的值,不完整的块暴力修改在区间内的部分,然后对整个块排序。
    对于查询操作,区间内完整的块二分查找C-add[i]在区间内的位置,然后用该位置减去块的首位置,不完整的块暴力统计。

    #define FILE_PC() freopen("C:\Users\hz\Desktop\in.txt","r",stdin)
    #include <algorithm>
    #include <cmath>
    #include <cstdio>
    #include <cstdlib>
    #include <cstring>
    
    using namespace std;
    const int maxn = 1000005;
    const int maxdiv = 1005;
    int a[maxn],b[maxn];
    int l[maxdiv],r[maxdiv],add[maxdiv];
    int lendiv,n,m;
    
    int main() {
    //    FILE_PC();
        scanf("%d%d",&n,&m);
        for(int i=1; i<=n; i++) {
            scanf("%d",a+i);
            b[i] = a[i];
        }
        lendiv = (int)sqrt(n); //分块长度
        int cntdiv = 0,flag = 1;
        for(int i=1; i<=n; i++) {
            if(cntdiv==0)l[++cntdiv] = i;//块的编号从1开始
            if(!flag) {
                l[++cntdiv] = i;
                flag = 1;
            }
            if(i%lendiv==0) {
                r[cntdiv] = i;
                flag = 0;
            }
        }
        r[cntdiv] = n; //最后一块的右区间
        for(int i=1; i<=cntdiv; i++) {
            sort(b+l[i],b+r[i]+1);
        }//每个块里面的元素排序
        for(int ca=0; ca<m; ca++) {
            char s[20];
            int ll,rr,cc;
            scanf("%s%d%d%d",s,&ll,&rr,&cc);
            if(s[0]=='M') {
                int ld = (int)(lower_bound(l+1,l+cntdiv+1,ll)-l);
                if(l[ld]!=ll) {
                    for(int i=ll; i<min(l[ld],rr+1); i++) {
                        a[i]+=cc;
                    }
                    for(int i=l[ld-1]; i<=r[ld-1]; i++) {
                        b[i] = a[i];
                    }
                    sort(b+l[ld-1],b+r[ld-1]+1);//重新对这个块排序
                }
                if(l[ld]<rr+1) {
                    int rd = (int)(lower_bound(r+1,r+cntdiv+1,rr)-r);
                    if(rr!=r[rd]) {
                        for(int i=max(ll,r[rd-1]+1); i<=rr; i++) {
                            a[i] += cc;
                        }
                        for(int i=l[rd]; i<=r[rd]; i++) {
                            b[i] = a[i];
                        }
                        sort(b+l[rd],b+r[rd]+1);//同上
                    }
                    for(int i=ld; i<=((rr==r[rd])?rd:rd-1); i++) { //完整的块
                        add[i]+=cc;
                    }
                }
            } else {
                int ans = 0;
                int ld = (int)(lower_bound(l+1,l+cntdiv+1,ll)-l);//给定的左区间落在哪一块
                if(l[ld]!=ll) {
                    for(int i=ll; i<min(l[ld],rr+1); i++) { //暴力统计不完整的块
                        if(a[i]+add[ld-1]>=cc)ans++;
                    }
                }
                if(l[ld]<rr+1) {
                    int rd = (int)(lower_bound(r+1,r+cntdiv+1,rr)-r);//给定的右区间落在哪一块
                    if(rr!=r[rd]) {
                        for(int i=max(ll,r[rd-1]+1); i<=rr; i++) { //同上
                            if(a[i]+add[rd]>=cc)ans++;
                        }
                    }
                    for(int i=ld; i<=((rr==r[rd])?rd:rd-1); i++) { //统计每一个完整的块
                        ans += (int)(b+r[i]+1-lower_bound(b+l[i],b+r[i]+1,cc-add[i]));
                    }
                }
                printf("%d
    ",ans);
            }
        }
        return 0;
    }
    
  • 相关阅读:
    Trapping Rain Water
    Construct Binary Tree from Preorder and Inorder Traversal
    Flatten Binary Tree to Linked List
    Permutations II
    Unique Paths II
    Path Sum II
    Unique Binary Search Trees II
    evdev module-----uinput.py
    evdev module-----events.py
    evdev module-----device.py
  • 原文地址:https://www.cnblogs.com/NeilThang/p/9356615.html
Copyright © 2011-2022 走看看