CodeChef FNCS (分块+树状数组)
题目:https://www.codechef.com/problems/FNCS
题解:
我们知道要求区间和的时候,我们用前缀和去优化。这里也是一样,我们要求第 l 个函数到第 r 个函数 [l, r] 的函数和,那么我们可以用 sum[r] - sum[l-1] 来求得。
由于这个数据量有点大,所以我们将函数分块。
例如样例:
1 3 有5个函数,那么我们分成3块。{ [1 3] , [2 5] }, { [4 5], [3 5] }, { [1 2] }。每一块对应都有一个sum ,这时如果我们要求前3个函数的和,就可以 (第一块的sum + 第3个函数的和)
2 5 在一个块内暴力的复杂度是O(sqrt(n))
4 5
3 5 还有就是在处理块内函数总sum 记录下每一个a[i] 对应的权值。比如在第一块中 1 2 2 1 1 分别是a1~a5对这一块sum 的贡献。
1 2
更新的时候就维护一下就可以了
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <string> 5 #include <algorithm> 6 #include <cmath> 7 #include <vector> 8 #include <queue> 9 #include <map> 10 #include <stack> 11 #include <set> 12 using namespace std; 13 typedef long long LL; 14 typedef unsigned long long uLL; 15 #define ms(a, b) memset(a, b, sizeof(a)) 16 #define pb push_back 17 #define mp make_pair 18 const LL INF = 0x7fffffff; 19 const int inf = 0x3f3f3f3f; 20 const int mod = 1e9+7; 21 const int maxn = 100000+10; 22 const int maxm = 1000000+10; 23 int a[maxn], l[maxn], r[maxn], Add[maxn]; 24 int unit, num, n; 25 int cnt[1000][maxn];//记录在第i块,j值的权 26 uLL sum[1000];//块的sum 27 uLL BIT_SUM[maxn]; 28 int low_bit(int x) 29 { 30 return x&-x; 31 } 32 uLL BIT_sum(int x) 33 { 34 uLL ret = 0; 35 while(x>0){ 36 ret += 1uLL*BIT_SUM[x]; x -= low_bit(x); 37 } 38 return ret; 39 } 40 void add(int x, int d) 41 { 42 while(x<=n){ 43 BIT_SUM[x] += d; x+=low_bit(x); 44 } 45 } 46 uLL query(int x) 47 { 48 return 1uLL*BIT_sum(x); 49 } 50 uLL Query(int x) 51 { 52 int end_unit = x/unit + 1; 53 LL ans = 0; 54 for(int i = 1;i<end_unit;i++) 55 ans += sum[i]; 56 for(int i = (end_unit-1)*unit+1;i<=x;i++) 57 ans += query(r[i]) - query(l[i]-1); 58 return ans; 59 } 60 void init() 61 { 62 ms(BIT_SUM, 0); 63 ms(sum, 0); 64 ms(cnt, 0); 65 } 66 int main() { 67 #ifdef LOCAL 68 freopen("input.txt", "r", stdin); 69 // freopen("output.txt", "w", stdout); 70 #endif 71 // ios::sync_with_stdio(0); 72 // cin.tie(0); 73 init(); 74 scanf("%d", &n); 75 for(int i = 1;i<=n;i++){ 76 scanf("%d", &a[i]); 77 add(i, a[i]); 78 } 79 for(int i = 1;i<=n;i++) scanf("%d%d", &l[i], &r[i]); 80 unit = (int)sqrt(n);//块的大小 81 num = (n-1)/unit+1;//块的数量 82 for(int i = 1;i<=num;i++){ 83 int begin_f = (i-1)*unit+1;//这一块的开始函数 84 int end_f = begin_f + unit - 1;//结束函数 85 ms(Add,0); 86 for(int j = begin_f;j<=end_f&&j<=n;j++){ 87 Add[l[j]]++;Add[r[j]+1]--; 88 } 89 int add = 0; 90 for(int j = 1;j<=n;j++){ 91 add += Add[j]; 92 cnt[i][j] += add; 93 } 94 for(int j = 1;j<=n;j++) 95 sum[i] += 1uLL * a[j] * cnt[i][j]; 96 // for(int j = 1;j<=n;j++) 97 // cout << cnt[i][j] <<" ";cout << endl; 98 // cout << sum[i] << endl; 99 } 100 int q;scanf("%d", &q); 101 while(q--){ 102 int op;scanf("%d", &op); 103 if(op==1){ 104 int x, y;scanf("%d%d", &x, &y); 105 for(int i = 1;i<=num;i++) 106 sum[i] -= 1uLL * a[x] * cnt[i][x]; 107 add(x, y-a[x]); 108 a[x] = y; 109 for(int i = 1;i<=num;i++) 110 sum[i] += 1uLL * a[x] * cnt[i][x]; 111 }else{ 112 int x, y; 113 scanf("%d%d", &x, &y); 114 uLL ans = Query(y) - Query(x-1); 115 printf("%llu\n", ans); 116 } 117 } 118 return 0; 119 }