O - 卿学姐种美丽的花
Time Limit: 8000/4000MS (Java/Others) Memory Limit: 125535/65535KB (Java/Others)
众所周知,在喵哈哈村,有一个温柔善良的卿学姐。
卿学姐喜欢和她一样美丽的花。所以卿学姐家的后院有很多的花坛。
卿学姐有 n 个花坛,一开始第 i i个花坛里有 A[i] 朵花。每过一段时间,卿学姐都会在花坛里种上新的花。
作为一个聪明的学姐,卿学姐的种花方式也是与众不同 , 每一次,卿学姐会在第 x x个花坛种上 y y朵花,然后在第 x+1 个花坛
上种上 y−1 朵花,再在第 x+2 个花坛上种上 y−2 朵花......以此类推,直到种到最后一个花坛,或者不需要种花为止。
喵哈哈的村民们都喜欢去卿学姐的后院赏花,沈宝宝也不例外。然而沈宝宝可不是省油的灯,怎么可能会老老实实地赏花呢。
每次沈宝宝来时,都会随机询问卿学姐在第 i i个花坛有多少朵花。
花坛的花实在太多了,卿学姐实在是数不过来。于是现在她向你求助,希望你能帮她数出花坛里多少朵花。
Input
第一行输入两个整数,花坛个数 N N和操作次数 Q Q。
第二行 N 个整数 A[1],A[2],A[3].....A[N] 。 ( 1≤A[i]≤231 )
接下来 Q 行,每行一个操作。
-
1 x y
表示卿学姐会在 x x号花坛种 y y朵花,并按相应的规律在后面的花坛上种花。 -
2 x
表示沈宝宝问卿学姐第 x x个花坛有多少朵花。
数据保证:
-
1≤N≤106
-
1≤Q≤2∗106
-
对于操作 1 , 1≤x≤N , 1≤y≤109
-
对于操作 2 , 1≤x≤N
Output
对于每个询问操作,按顺序输出答案对 772002+233 取模的值。
Sample input and output
Sample Input | Sample Output |
---|---|
6 3 1 2 3 2 1 2 1 2 3 2 3 2 6 | 5 2 |
Source
2016 UESTC Training for Data Structures Problem O
My Solution
树状数组+等差数列
更的时候 Ax = A0 + (x-x0)*(-1)
所以Ax求和并加上初始值就是新的val[x]了,这个最后加上初始值直接输出就行
sum(Ax) = sum(A0+x0) - sum(x更新的次数)
然后A0 + x0用一个树状数组维护,在更新点add(x0, A0+x0); 并在更新结尾的地方 add(x0+y0, -(x0+y0)),
这样用树状数组地方get()的时候就不会对后面没有更新到的地方有影响了
用另一个数组维护x出现的次数,在更新点add(x0, 1); 并在更新结尾的地方 add(x0+y0, -1), 同理对后面没有影响了
复杂度 O(q*logn)
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
typedef long long LL;
const int maxn = 1e6 +8;
//!A0 = sum(A0 + (x-x0)*(-1) ); ==> Ax = sum(A0+x0) - sum(x被更新的次数)
LL Tree[maxn], Tree2[maxn]; //Tree 记录 sum( ) Tree 记录 x 被更新的次数
int n, val[maxn];
inline int lowbit(int x)
{
return (x&-x);
}
void add(int x, int value)
{
for(int i = x; i <= n; i+= lowbit(i))
Tree[i] += value;
}
LL get(int x)
{
LL sum = 0;
for(int i = x;i;i-=lowbit(i))
sum+=Tree[i];
return (sum);
}
//Tree2
void add2(int x, int value)
{
for(int i = x; i <= n; i+= lowbit(i))
Tree2[i] += value;
}
LL get2(int x)
{
LL sum = 0;
for(int i = x;i;i-=lowbit(i))
sum+=Tree2[i];
return (sum);
}
int main()
{
#ifdef LOCAL
freopen("a.txt", "r", stdin);
#endif // LOCAL
int q;
memset(Tree, 0, sizeof Tree);
memset(Tree2, 0, sizeof Tree2);
scanf("%d%d", &n, &q);
for(int i = 1; i <= n; i++){
scanf("%d", &val[i]);
}
int op, x, y;
while(q--){
scanf("%d", &op);
if(op == 1){
scanf("%d%d", &x, &y);
add(x, x+y);
if(x+y <= n) add(x+y, -(x+y)); //!在更新的结尾处加上个 - (x+y) 这样对后面没有更新到的地方就没有影响了 后面都抵消为 0 了
add2(x, 1);
if(x+y <= n) add2(x+y, -1); //!在更新的结尾处加上个 - 1 这样对后面没有更新到的地方就没有影响了 后面都抵消为 0 了
}
else{
scanf("%d", &x);
//t = -get(x-1);
LL ans = get(x) - x*get2(x) + val[x];
printf("%d\n", int( ans % (772002+233))); //get(0) == 0
}
}
return 0;
Thank you!