• 【分块】三


    开头日常感谢hzw学长

    终于到达本组题了呼

    本组成员:老司机hgz,可爱的lln同学and帅气可爱天真无邪的我。

    题面(咳咳咳才不是为了黑ty)

    题目描述

    题目背景:

    国民男神ty又遇到了一个小难题,他在和xqj大神的争论中(谁更强),ty表示自己不会这个问题(装弱),于是他将这个问题交给了身为ty小迷弟(妹)的你。

    题目描述:

    给一个长为n的数列,以及n次操作。每次操作均有一个操作3个数字组成(operate,l,r,x操作共有两种

    0l~r区间每个数加上x

    1询问l~r区间内小于某个值x的前驱(比其小的最大元素),若不存在则输出-1

    输入

    第一行:一个整数n,表示数列长为n,以及有n次操作。

    第二行:n个数,表示原来的数列。

    3~n+2行:每行四个数:operate,l,r,x,分别表示操作的类型、区间l~r,和加入的元素x

    输出

    n行,每行一个数,输出lr区间内小于某个值x的前驱(比其小的最大元素)。

    样例输入

    3

    1 2 3

    1 1 2 2

    0 1 2 1

    1 1 2 2

     

    样例输出

    1
    -1

    提示

    对于50%的数据 n<=1000

    对于100%的数据 n<=30000

    保证运算过程中数据不超过64位整数

    保证数据全部随机

    【格式什么的就不要介意了吧嘤嘤嘤】

    【分析】

    题目大意是给出一个长为n的数列,以及n个操作,操作涉及区间加法,询问区间内小于某个值x的前驱(比其小的最大元素)。

    与第二道题目其实没有本质上的区别。但这里还是进行一下解释(就当前面几道没有做过)。

    本题运用分块来做可以提高解题效率。

    令每一个块的大小为m,把整个序列分成n/m块。我们可以知道,当mn/m尽量平衡的时候,程序的效率是最高的,所以我们把这个数列分成√n块。

    预备:有若干个数组abblocktaga用来处理一个序列中非完整块的数的状态,b则用来处理一个序列中完整块的数的状态,block指每个数所在的块的序,tag用来储存每个完整块的增加量(tag的使用在后面修改状态下会进行阐述)

    我们先来考虑查询的状态(可以理解为本道题是为了查询而修改的),已知lr,首先l~r中完整的块可以直接进行二分查找每个块找出符合题意的一个数,这个查询在b数组中进行(可以直接对查询的x-tag[i]方便处理),非完整的块的数在a数组中暴力进行。所有的数在查询过程的依次比较得出符合题目要求的最大值。

    然后是考虑修改状态,仍旧是l~r的区间中,完整的块我们可以直接在此区间的tag[i]中加上x,非完整的块我们对此在a数组中暴力加法,然后对其修改的值在b数组中排序叠加,这样即可为下次查询服务。

    其他细节可以看ac代码。

    ac代码

    #include <map>
    #include <set>
    #include <cmath>
    #include <stack>
    #include <queue>
    #include <cstdio>
    #include <vector>
    #include <cstring>
    #include <cstdlib>
    #include <iostream>
    #include <algorithm>
    #define mod 998244353
    #define pi acos(-1)
    #define inf 0x7fffffff
    #define ll long long
    using namespace std;
    ll read()
    {
        ll x = 0, f = 1;
        char ch = getchar();
        while (ch < '0' || ch > '9')
        {
            if (ch == '-')
                f = -1;
            ch = getchar();
        }
        while (ch >= '0' && ch <= '9')
        {
            x = x * 10 + ch - '0';
            ch = getchar();
        }
        return x * f;
    }
    ll n, blo;
    ll v[50005], bl[50005], atag[50005];
    vector<ll> ve[505];
    void reset(ll x)
    {
        ve[x].clear();
        for (ll i = (x - 1) * blo + 1; i <= min(x * blo, n); i++)
            ve[x].push_back(v[i]);
        sort(ve[x].begin(), ve[x].end());
    }
    void add(ll a, ll b, ll c)
    {
        for (ll i = a; i <= min(bl[a] * blo, b); i++)
            v[i] += c;
        reset(bl[a]);
        if (bl[a] != bl[b])
        {
            for (ll i = (bl[b] - 1) * blo + 1; i <= b; i++)
                v[i] += c;
            reset(bl[b]);
        }
        for (ll i = bl[a] + 1; i <= bl[b] - 1; i++)
            atag[i] += c;
    }
    ll query(ll a, ll b, ll c)
    {
        ll ans = -1;
        for (ll i = a; i <= min(bl[a] * blo, b); i++)
            if (v[i] + atag[bl[a]] < c)
                ans = max(ans, atag[bl[a]] + v[i]);
        if (bl[a] != bl[b])
            for (ll i = (bl[b] - 1) * blo + 1; i <= b; i++)
                if (v[i] + atag[bl[b]] < c)
                    ans = max(ans, v[i] + atag[bl[b]]);
        for (ll i = bl[a] + 1; i <= bl[b] - 1; i++)
        {
            ll x = c - atag[i];
            vector<ll>::iterator it1 = lower_bound(ve[i].begin(), ve[i].end(), x);
            if (it1 != ve[i].begin())
            {
                it1--;
                ans = max(ans, *it1 + atag[i]);
            }
        }
        return ans;
    }
    int main()
    {
        freopen("lln.in", "r", stdin);
        freopen("lln.out", "w", stdout);
        n = read();
        blo = sqrt(n);
        for (ll i = 1; i <= n; i++)
            v[i] = read();
        for (ll i = 1; i <= n; i++)
        {
            bl[i] = (i - 1) / blo + 1;
            ve[bl[i]].push_back(v[i]);
        }
        for (ll i = 1; i <= bl[n]; i++)
            sort(ve[i].begin(), ve[i].end());
        for (ll i = 1; i <= n; i++)
        {
            ll f = read(), a = read(), b = read(), c = read();
            if (f == 0)
                add(a, b, c);
            if (f == 1)
                printf("%lld
    ", query(a, b, c));
        }
        fclose(stdin);
        fclose(stdout);
        return 0;
    }

    (草率了事的我先逃一步)

  • 相关阅读:
    学习Linux shell脚本中连接字符串的方法
    使用 ffmpeg 转换视频格式
    一点不懂到小白的linux系统运维经历分享
    linux利用scp远程上传下载文件/文件夹
    angular ui-select
    JavaScript sort()方法
    js性能优化
    layer弹出层
    JS复制对象
    某天修改了啥bat批处理
  • 原文地址:https://www.cnblogs.com/Hathawaxy/p/6894876.html
Copyright © 2020-2023  润新知