传送门
第一行一个整数T,表示有T组数据。
每组数据第一行一个正整数N(N<=50000),表示有N个数,接下来有N个正整数,
接下来每行有一条命令,命令有4种形式:
(1) Add i j, 表示第i个数增加j(j不超过30)
(2)Sub i j , 表示第i个数减少j(j不超过30);
(3)Query i j ,i<=j,表示询问 第 i 到第 j 个数的总和;
(4)End 表示结束,这条命令在每组数据最后出现;
每组数据最多有40000条命令
分析:
线段树点更新,线段树区间求和 的 模板题。
利用树型结构可以很高效的求解这个问题。
采用的是二分的思想。
O(logn)的复杂度
/***
* 线段树点更新,区间求和
****/
#include <iostream>
#include <string>
using namespace std;
const int N1 = 5*1e4+10;
const int N2 = N1*4;
int a[N1];
int sum[N2];
void pushup(int root)
{
sum[root] = sum[root*2] + sum[root*2+1];
}
void build(int L,int R,int rt)
{
if(L == R)
{
sum[rt] = a[L];
return ;
}
int M = (L+R)/2;
build(L,M,rt*2);
build(M+1,R,rt*2+1);
pushup(rt);
}
// 更新最下面节点的值,而且要更新上面和他关联的节点的值
void update(int rt,int pos,int num,int L,int R)
{
if(L == R)
{
sum[rt] += num;
return ;
}
int M = (L+R)/2;
if(pos <= M)
update(rt*2,pos,num,L,M);
else
update(rt*2+1,pos,num,M+1,R);
pushup(rt);
}
// 区间求和(l~r)区间
int query(int rt,int l,int r,int L,int R)
{
if(l == L && r == R)
return sum[rt];
int ans = 0;
int M = (L+R)/2;
// 如果要求的区间和 在当前节点的 左半个区间内
if(r <= M)
ans += query(rt*2, l, r, L, M);
// 如果要求的区间和 在当前节点的 右半个区间内
else if(l > M)
ans += query(rt*2+1,l,r, M+1,R);
// 要求的区间和 横跨当前节点的左边和右边
else
{
ans += query(rt*2,l,M,L,M);
ans += query(rt*2+1,M+1,r,M+1,R);
}
return ans;
}
int main()
{
ios::sync_with_stdio(false);
int T;
cin >> T;
for(int ti = 1; ti <= T; ti++)
{
int n;
string t;
cin >> n;
for(int i = 1; i <= n; i++)
cin >> a[i];
// 建立线段树
build(1,n,1);
cout << "Case "<< ti << ":" << endl;
while(cin >> t)
{
if(t == "End") break;
int t1,t2;
cin >> t1 >> t2; //a[t1] 增加或减少t2
if(t == "Add") // 增加
update(1,t1,t2,1,n);
else if(t == "Sub") // 减少
update(1,t1,-t2,1,n);
else // 求和
{
int ans = query(1,t1,t2,1,n);
cout << ans << endl;
}
}
}
return 0;
}