zoukankan      html  css  js  c++  java
  • LibreOJ

    题目描述

    给出一个长为n的数列,以及n个操作,操作涉及区间加法,询问区间内小于某个值x的元素个数。

    输入格式

    第一行输入一个数字 。

    第二行输入n个数字,第i个数字为ai,以空格隔开。

    接下来输入n行询问,每行输入四个数字opt,l,r,c,以空格隔开。

    若opt=0,表示将位于l,r的之间的数字都加c。

    若opt=1,表示询问l,r中,小于c^2的数字的个数。

    输出格式

    对于每次询问,输出一行一个数字表示答案。

    样例

    样例输入

    4

    1 2 2 3

    0 1 3 1

    1 1 3 2

    1 1 4 1

    1 2 3 2

    样例输出

    3

    0

    2

    和上一题类似,不过这个题线段树就无能为力了。按照线段树大段维护,局部朴素的思想,我们建立两个数组a和b,其中a是在原数组之上进行操作后的数组,b数组是a数组的拷贝,但同时每一块内的元素是有序的。对于修改,分为端点在一块内/不在一块内,边角块直接暴力,中间的块利用add数组(类似线段树的lazy tag)进行标记。注意,边角块处理完后一定要对b数组中边角块位置的数进行重新排序!查询类似,注意在中间块中直接对每段用lower_bound函数查找即可。

    需要注意的细节:排序函数sort(b + L[i], b + R[i] + 1);右边别忘+1!坑了半天TAT

    #include <bits/stdc++.h>
    using namespace std;
    int a[500005], b[500005], add[500005];  
    int L[500005], R[500005];
    int pos[500005];
    int n, t;
    inline int read(){   int s=0,w=1;   char ch=getchar();   while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}   while(ch>='0'&&ch<='9') s=s*10+ch-'0',ch=getchar();   return s*w;}
    void change(int l, int r, int d) {
        int p = pos[l], q = pos[r];
        if (p == q) {
            for (int i = l; i <= r; i++) a[i] += d;
            for (int i = L[p]; i <= R[p]; i++) 
            {
                a[i] += add[p];
                b[i] = a[i];
            }
            add[p] = 0;
            sort(b + L[p], b + R[p] + 1);
        } else {
            for (int i = p + 1; i <= q - 1; i++) add[i] += d;
            for (int i = l; i <= R[p]; i++) a[i] += d;
            for (int i = L[p]; i <= R[p]; i++) 
            {
                a[i] += add[p];
                b[i] = a[i];
            }
            add[p] = 0;
            sort(b + L[p], b + R[p] + 1);
            for (int i = L[q]; i <= r; i++) a[i] += d;
            for (int i = L[q]; i <= R[q]; i++) 
            {
                a[i] += add[q];
                b[i] = a[i];
            }
            add[q] = 0;
            sort(b + L[q], b + R[q] + 1);
        }
    }
    
    int ask(int l, int r, int c) {
        int p = pos[l], q = pos[r], ans = 0;
        if (p == q) {
            for (int i = l; i <= r; i++)
                if (a[i] + add[p] < c)
                    ans++;
            return ans;
        } else {
            for (int i = p + 1; i <= q - 1; i++) {
                int ppos = lower_bound(b + L[i], b + R[i] + 1, c - add[i]) - b;
                if(ppos != R[i] + 1) ans += ppos - L[i];
                else ans += R[i] - L[i] + 1;
            }
            for (int i = l; i <= R[p]; i++)
                if (a[i] + add[p] < c) ans++;
            for (int i = L[q]; i <= r; i++)
                if (a[i] + add[q] < c) ans++;
            return ans;
        }
    }
    int main() {
        cin >> n;
        memset(add, 0, sizeof(add));
        for (int i = 1; i <= n; i++) {
            a[i] = read();
            b[i] = a[i];
        }
        t = sqrt(n);
        for (int i = 1; i <= t; i++) {
            L[i] = (i - 1) * sqrt(n) + 1;
            R[i] = i * sqrt(n);
        }
        if (R[t] < n)
            t++, L[t] = R[t - 1] + 1, R[t] = n;
        for (int i = 1; i <= t; i++)
        {
            for (int j = L[i]; j <= R[i]; j++) {
                pos[j] = i;
            }
            sort(b + L[i], b + R[i] + 1);
        }
        for (int i = 1; i <= n; i++) {
            int opt, l, r, c;
            opt = read(), l = read(), r = read(), c = read();
            if (opt == 0) {
                change(l, r, c);
            } else {
                cout << ask(l, r, c * c) << endl;
            }
        }
    }
  • 相关阅读:
    golang ssh 相关
    javascript 常用正则表达式收集
    Mac下 shell文件双击可执行怎么写
    Python常用插件之BeautifulSoup4使用
    Python常用插件之Requests使用
    JavaScript学习-WeakSet
    javascript学习-Set
    Vue-大型项目下路由的模块拆分
    360兼容模式ie10不支持includes方法
    360兼容模式ie10及以下版本map对象和Set对象没有定义
  • 原文地址:https://www.cnblogs.com/lipoicyclic/p/13299217.html
Copyright © 2011-2022 走看看