ICPC网络赛 Ryuji doesn't want to study (线段树/树状数组)
程序员文章站
2022-07-13 11:23:44
...
Ryuji doesn’t want to study
题目链接: 计蒜客 - 题库链接
题意
给你N个数,M个询问,有两种操作
- 将一个数修改为另一个值
- 求区间和
数据范围:
思路
前缀和思想
要求的和很奇怪,第一个数要出现N次,第二个数要出现N-1次,这种单调性质,我就想到了前缀和。那么现在我的目标就是如何快速求前缀和的区间和,我本来想在开一个树状数组快速的查询前缀和的前缀和,但是如果要修改一个点x的值,就需要修改 的值仅依靠树状数组显然不行,我就用了线段树区间修改。所以我这是单点查询区间修改。
从图像找规律
看图,用两个树状数组实现。
代码
线段树
#include <bits/stdc++.h>
using namespace std;
#define rep(i,j,k) for(ll i = (ll)j;i <= (ll)k;i ++)
#define per(i,j,k) for(ll i = (ll)j;i >= (ll)k;i --)
#define debug(x) cerr<<#x<<" = "<<(x)<<endl
#define mmm(a,b) memset(a,b,sizeof(a))
#define pb push_back
typedef double db;
typedef long long ll;
const ll MAXN = (ll)1e5+7;
const ll INF = (ll)0x3f3f3f3f;
#define lson rt<<1
#define rson rt<<1|1
ll N,M;
ll A[MAXN];
ll sum[MAXN<<2];
ll add[MAXN<<2];
void PushUp(ll rt){sum[rt] = sum[lson] + sum[rson]; }
void Build(ll l,ll r,ll rt){
if (l == r){
sum[rt] = A[l];
return ;
}
ll m = (l+r)>>1;
Build(l,m,lson);
Build(m+1,r,rson);
PushUp(rt);
}
void PushDown(ll rt,ll ln,ll rn){
if (add[rt]){
sum[lson] += add[rt]*ln;
sum[rson] += add[rt]*rn;
add[lson] += add[rt];
add[rson] += add[rt];
add[rt] = 0;
}
}
void Update(ll L,ll R,ll C,ll l,ll r,ll rt){
if (L <= l && r <= R){
sum[rt] += C*(r+1-l);
add[rt] += C;
return ;
}
ll m = (l+r)>>1;
PushDown(rt,m+1-l,r-m);
if (L <= m) Update(L,R,C,l,m,lson);
if (R > m) Update(L,R,C,m+1,r,rson);
PushUp(rt);
}
ll Query(ll L,ll R,ll l,ll r,ll rt){
if (L == 0) return 0;
if (L <= l && r <= R){
return sum[rt];
}
ll m = (l+r)>>1;
PushDown(rt,m+1-l,r-m);
ll ans = 0;
if (L <= m) ans += Query(L,R,l,m,lson);
if (R > m) ans += Query(L,R,m+1,r,rson);
return ans;
}
int main()
{
scanf("%lld %lld",&N,&M);
ll sum = 0;
rep(i,1,N) {
ll tmp;
scanf("%lld",&tmp);
A[i] = A[i-1]+tmp;
}
Build(1,N,1);
while (M --){
ll a,b,c;
scanf("%lld %lld %lld",&a,&b,&c);
if (a == 1) {
ll sum = 0;
sum = Query(b,c,1,N,1);
sum -= Query(b-1,b-1,1,N,1)*(c-b+1);
printf("%lld\n",sum);
}else {
Update(b,N,c-Query(b,b,1,N,1)+Query(b-1,b-1,1,N,1),1,N,1);
}
}
}
树状数组
#include <bits/stdc++.h>
using namespace std;
#define rep(i,j,k) for(ll i = (ll)j;i <= (ll)k;i ++)
#define per(i,j,k) for(ll i = (ll)j;i >= (ll)k;i --)
#define debug(x) cerr<<#x<<" = "<<(x)<<endl
#define mmm(a,b) memset(a,b,sizeof(a))
#define pb push_back
typedef double db;
typedef long long ll;
const ll MAXN = (ll)1e6+7;
const ll INF = (ll)0x3f3f3f3f;
ll A[MAXN],B[MAXN],N,M;
ll lowbit(ll x) {return x&(-x); }
void update(ll L,ll val) {
while (L <= N) {
A[L] += val;
L += lowbit(L);
}
}
ll getsum(ll L) {
ll sum = 0;
while (L > 0) {
sum += A[L];
L -= lowbit(L);
}
return sum;
}
void update2(ll L,ll val) {
while (L <= N) {
B[L] += val;
L += lowbit(L);
}
}
ll getsum2(ll L) {
ll sum = 0;
while (L > 0) {
sum += B[L];
L -= lowbit(L);
}
return sum;
}
int main()
{
scanf("%lld %lld",&N,&M);
rep(i,1,N) {
ll tmp;
scanf("%lld",&tmp);
update(i,tmp);
update2(i,tmp*(N-i+1));
}
rep(i,1,M) {
ll op,x,y;
scanf("%lld %lld %lld",&op,&x,&y);
if (op == 1) {
ll ans1 = getsum2(y) - getsum2(x-1);
ll ans2 = getsum(y) - getsum(x-1);
printf("%lld\n",ans1-ans2*(N-y));
}else {
ll dif = getsum(x) - getsum(x-1);
update(x,y-dif);
update2(x,(y-dif)*(N-x+1));
}
}
}
推荐阅读
-
【计蒜客】2018ICPC徐州赛区网络赛H Ryuji doesn't want to study(树状数组)
-
ACM-ICPC 2018 徐州赛区网络预赛 H - Ryuji doesn't want to study
-
ACM-ICPC 2018 徐州赛区网络预赛 H. Ryuji doesn't want to study(线段树区间求和)
-
ACM-ICPC 2018 徐州赛区网络预赛 H. Ryuji doesn't want to study—— 树状数组
-
ACM-ICPC 2018 徐州赛区网络预赛 H Ryuji doesn't want to study(线段树 两种做法)
-
ICPC网络赛 Ryuji doesn't want to study (线段树/树状数组)
-
ACM-ICPC 2018 徐州赛区网络预赛 - H Ryuji doesn't want to study - 线段树