LGP2801 教主的魔法
题目链接 : 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\n", query(x, y, z)); 76 } 77 return 0; 78 }