[Luogu P2801]教主的魔法

题意就是让我们维护一个数据结构,可以实现区间修改和区间查询多少个数大于等于给定值。这个据说线段树可以写但是我并没有想到qwq,于是我使用了“优雅的暴力”——分块。

分块做法十分显然,我们维护大小为√n的块(√n的块根据均值不等式复杂度取得最小值),维护一个lazy标记,区间修改的话,如果修改的区间是包含整个块就直接对lazy标记操作,如果是半个块就直接暴力修改就行。而查询操作要是直接找和暴力没啥区别。注意到块的大小其实也就最多1000,所以考虑排序之后二分查找,这样就ok了。

时间复杂度为O(q√(nlogn))。

其实思路非常简单,但是分块这个东西比较玄学,稍稍一个符号改动说不定就可以多水好多数据,就像我提交记录有10、20、60、80、90最后AC。debug时间大约是一个多小时qwq。

#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<queue>
#include<iostream>
#include<vector>
#define N 1000010
using namespace std;
int block[N],size,lazy[N],a[N],n,q;
vector<int>b[10001];
void reset(int x)
{
    b[x].clear();
    for(int i = (x - 1) * size + 1;i <= min(x * size,n);i++) b[x].push_back(a[i]);//不能直接对原序列排序,拿一个备用序列排序
    sort(b[x].begin(),b[x].end());
}
void add(int l,int r,int k)
{
    if(block[l] == block[r])//区间在一个块里直接暴力操作
    {
        for(int i = l;i <= r;i++) a[i] += k;
        reset(block[l]);
        return;
    }
    for(int i = block[l] + 1;i <= block[r] - 1;i++) lazy[i] += k;//整个块就对lazy标记操作
    for(int i = l;i <= block[l] * size;i++) a[i] += k;
    reset(block[l]);
    for(int i = r;i > (block[r] - 1) * size;i--) a[i] += k;
    reset(block[r]);
    return;
}
int query(int l,int r,int k)
{
    int ret = 0;
    if(block[l] == block[r])
    {
        for(int i = l;i <= r;i++) if(a[i] + lazy[block[l]] >= k) ret++;
        return ret;
    }
    for(int i = block[l] + 1;i <= block[r] - 1;i++)
    {
        ret += b[i].end() - b[i].begin() - (lower_bound(b[i].begin(),b[i].end(),k - lazy[i]) - b[i].begin());//二分查找多少个数比(k - lazy[i])大。
    }
    for(int i = l;i <= block[l] * size;i++) if(a[i] + lazy[block[i]] >= k) ret++;
    for(int i = r;i > (block[r] - 1) * size;i--) if(a[i] + lazy[block[i]] >= k) ret++;
    return ret;
}
int main()
{
    scanf("%d %d",&n,&q);
    size = (int)sqrt(n);
    for(int i = 1;i <= n;i++)
    {
        scanf("%d",&a[i]);
        block[i] = (i - 1) / size + 1;
        b[block[i]].push_back(a[i]);
    }
    for(int i = 1;i <= block[n];i++) sort(b[i].begin(),b[i].end());
    while(q--)
    {
        int l,r,k;char op;
        cin >> op;
        scanf("%d%d%d",&l,&r,&k);
        if(op == ‘A‘) printf("%d\n",query(l,r,k));
        else add(l,r,k);
    }
    return 0;
}

原文地址:https://www.cnblogs.com/lijilai-oi/p/10991545.html

时间: 2024-10-18 01:09:13

[Luogu P2801]教主的魔法的相关文章

Luogu 2801 教主的魔法 | 分块模板题

Luogu 2801 教主的魔法 | 分块模板题 我犯的错误: 有一处l打成了1,还看不出来-- 缩小块大小De完bug后忘了把块大小改回去就提交--还以为自己一定能A了-- #include <cstdio> #include <cstring> #include <algorithm> #include <set> using namespace std; typedef long long ll; #define space putchar(' ')

洛谷 P2801 教主的魔法 题解

此文为博主原创题解,转载时请通知博主,并把原文链接放在正文醒目位置. 题目链接:https://www.luogu.org/problem/show?pid=2801 题目描述 教主最近学会了一种神奇的魔法,能够使人长高.于是他准备演示给XMYZ信息组每个英雄看.于是N个英雄们又一次聚集在了一起,这次他们排成了一列,被编号为1.2.…….N. 每个人的身高一开始都是不超过1000的正整数.教主的魔法每次可以把闭区间[L, R](1≤L≤R≤N)内的英雄的身高全部加上一个整数W.(虽然L=R时并不

BZOI——3343: 教主的魔法 || 洛谷—— P2801 教主的魔法

http://www.lydsy.com/JudgeOnline/problem.php?id=3343  ||  https://www.luogu.org/problem/show?pid=2801 题目描述 教主最近学会了一种神奇的魔法,能够使人长高.于是他准备演示给XMYZ信息组每个英雄看.于是N个英雄们又一次聚集在了一起,这次他们排成了一列,被编号为1.2.…….N. 每个人的身高一开始都是不超过1000的正整数.教主的魔法每次可以把闭区间[L, R](1≤L≤R≤N)内的英雄的身高全

洛谷 P2801 教主的魔法

题目描述 教主最近学会了一种神奇的魔法,能够使人长高.于是他准备演示给XMYZ信息组每个英雄看.于是N个英雄们又一次聚集在了一起,这次他们排成了一列,被编号为1.2.…….N. 每个人的身高一开始都是不超过1000的正整数.教主的魔法每次可以把闭区间[L, R](1≤L≤R≤N)内的英雄的身高全部加上一个整数W.(虽然L=R时并不符合区间的书写规范,但我们可以认为是单独增加第L(R)个英雄的身高) CYZ.光哥和ZJQ等人不信教主的邪,于是他们有时候会问WD闭区间 [L, R] 内有多少英雄身高

P2801 教主的魔法 (分块)

题目传送 长度为\(n(n\le 1000000)\)的数组,\(q(q\le 3000)\) 次操作.修改操作即将某个区间的值增加某个不大于1000的值,查询操作即查询某个区间比C大于等于的数有多少个 我们用一个数组\(add[i]\)来表示第\(i\)段增量,如果查询区间完全包含第\(i\)段,那么就相当于是在原数组中查找大于等于\(C-add[i]\)的数,怎么找?排序后二分找.而对于左右不完整的那部分,直接暴力查询就可以. 对于修改操作.整段的直接增加增量,不完整的直接修改原数组,然后重

【每日题解 #16】LGP2801 教主的魔法

题目链接 : P2801 教主的魔法 这是第一次A分块的题 就是模板题了 每个块内排序 每个整块仅需维护整块的修改量 询问操作: 对于边缘块 直接暴力找在[l, r]内 且比给定值大的有几个 对于整块 二分查找不小于 (给定值 - 本块修改量) 的块有多少个 修改操作: 边缘块直接修改 整块在修改量标记上修改 本题细节较多 尤其是修改和询问的范围 [明明是蒟蒻不熟练... 附上代码: 1 #include <cstdio> 2 #include <algorithm> 3 #inc

BZOJ3343 &amp; 洛谷2801:教主的魔法——题解

http://www.lydsy.com/JudgeOnline/problem.php?id=3343 https://www.luogu.org/problemnew/show/2801 题目描述 教主最近学会了一种神奇的魔法,能够使人长高.于是他准备演示给XMYZ信息组每个英雄看.于是N个英雄们又一次聚集在了一起,这次他们排成了一列,被编号为1.2.…….N. 每个人的身高一开始都是不超过1000的正整数.教主的魔法每次可以把闭区间[L, R](1≤L≤R≤N)内的英雄的身高全部加上一个整

教主的魔法(分块模板)

教主的魔法(luogu) Description 题目描述 教主最近学会了一种神奇的魔法,能够使人长高.于是他准备演示给XMYZ信息组每个英雄看.于是N个英雄们又一次聚集在了一起,这次他们排成了一列,被编号为1.2.…….N. 每个人的身高一开始都是不超过1000的正整数.教主的魔法每次可以把闭区间[L, R](1≤L≤R≤N)内的英雄的身高全部加上一个整数W.(虽然L=R时并不符合区间的书写规范,但我们可以认为是单独增加第L(R)个英雄的身高) CYZ.光哥和ZJQ等人不信教主的邪,于是他们有

刷题总结——教主的魔法(bzoj3343)

题目: Description 教主最近学会了一种神奇的魔法,能够使人长高.于是他准备演示给XMYZ信息组每个英雄看.于是N个英雄们又一次聚集在了一起,这次他们排成了一列,被编号为1.2.--.N. 每个人的身高一开始都是不超过1000的正整数.教主的魔法每次可以把闭区间[L, R](1≤L≤R≤N)内的英雄的身高全部加上一个整数W.(虽然L=R时并不符合区间的书写规范,但我们可以认为是单独增加第L(R)个英雄的身高) CYZ.光哥和ZJQ等人不信教主的邪,于是他们有时候会问WD闭区间 [L,