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

Posted hjmmm

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了每日题解 #16LGP2801 教主的魔法相关的知识,希望对你有一定的参考价值。

题目链接 : P2801 教主的魔法

这是第一次A分块的题

就是模板题了

每个块内排序 每个整块仅需维护整块的修改量 

询问操作:

对于边缘块 直接暴力找在[l, r]内 且比给定值大的有几个

对于整块 二分查找不小于 (给定值 - 本块修改量) 的块有多少个

修改操作:

边缘块直接修改

整块在修改量标记上修改

 

本题细节较多 尤其是修改和询问的范围

【明明是蒟蒻不熟练。。。

 

附上代码:

技术分享图片
 1 #include <cstdio>
 2 #include <algorithm>
 3 #include <cmath>
 4 using namespace std;
 5 const int N = 1e6 + 5;
 6 struct Node{
 7     int bl, id;
 8     long long x;
 9 }node[N]; 
10 int n, blo, q, ts;
11 long long atag[N];//修改量标记
12  
13 bool rule1(Node a, Node b){
14     return a.x < b.x;
15 }
16 //把[a, b]的元素加c
17 void add(int a, int b, long long c){
18     for(int i = (node[a].bl - 1) * blo + 1; i <= min(b, min(n, node[a].bl * blo)); i++)
19         if(node[i].id >= a)
20             node[i].x += c;
21     sort(node + (node[a].bl - 1) * blo + 1, node + min(n, node[a].bl * blo) + 1, rule1);
22     if(node[a].bl != node[b].bl)
23         for(int i = (node[b].bl - 1) * blo + 1; i <= min(n, node[b].bl * blo); i++)
24             if(node[i].id <= b)
25                 node[i].x += c;
26     sort(node + (node[b].bl - 1) * blo + 1, node + min(n, node[b].bl * blo) + 1, rule1);
27     for(int i = node[a].bl + 1; i <= node[b].bl - 1; i++)
28         atag[i] += c;    
29 }
30 //二分查找pos块中比a大的元素个数
31 int find(int pos, long long a){
32     if(a > node[min(n, pos * blo)].x) return 0;
33     int l = (pos - 1) * blo + 1, r = min(n, pos * blo), mid;
34     while(l < r){
35         mid = l + ((r - l) >> 1);
36         if(node[mid].x >= a) r = mid;
37         else l = mid + 1;
38     }
39     return min(n, pos * blo) - l + 1;
40 }
41 //询问 [a, b]中大于等于c的元素个数
42 int query(int a, int b, long long c){
43     int ans = 0;
44     for(int i = (node[a].bl - 1) * blo + 1; i <= min(b, min(n, node[a].bl * blo)); i++)
45         if(node[i].id >= a && node[i].x >= c - atag[node[a].bl]) 
46             ans++; 
47 
48     if(node[a].bl != node[b].bl) 
49         for(int i = (node[b].bl - 1) * blo + 1; i <= min(n, node[b].bl * blo); i++)
50             if(node[i].id <= b && node[i].x >= c - atag[node[b].bl]) 
51                 ans++;
52 
53     for(int i = node[a].bl + 1; i <= node[b].bl - 1; i++)
54         ans += find(i, c - atag[i]);
55     return ans;
56 }
57 
58 int main(){
59     scanf("%d%d", &n, &q);
60     blo = sqrt(n);
61     for(int i = 1; i <= n; i++) scanf("%d", &node[i].x);
62 //输入
63     for(int i = 1; i <= n; i++){
64         node[i].bl = (i - 1) / blo + 1;
65         node[i].id = i;
66     }
67     for(int i = 1; i <= node[n].bl; i++)
68         sort(node + (i - 1) * blo + 1, node + min(n, i * blo) + 1, rule1);
69 //块的分配与块内排序
70     char op[10];
71     int x, y, z;
72     for(int i = 1; i <= q; i++){
73         scanf("%s%d%d%d", op, &x, &y, &z);
74         if(op[0] == M) add(x, y, z);
75         else printf("%d
", query(x, y, z));
76     }
77     return 0;    
78 }
View Code

 

以上是关于每日题解 #16LGP2801 教主的魔法的主要内容,如果未能解决你的问题,请参考以下文章

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

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

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

洛谷 P2801 教主的魔法

P2801 教主的魔法 (分块)

[Luogu P2801]教主的魔法