题目连接:http://acm.nyist.edu.cn/JudgeOnline/problem.php?pid=123
这道题其实就是一个区间更新的问题,用线段树和树状数组都可以写,树状数组的话会方便很多(毕竟代码没有那么长),插线问点,其实就是在一个区间内更新的时候,比如更新x到y区间的话,就更新x到n区间的值,然后再让y+1到n的区间减去这个值就好了。而线段树的写法,最开始写之前我先查了一下有没有人用线段树写(其实我是怕好不容易写完了那么多代码后tle),然后发现好像用lazy数组标记的话会超时(我没试,t不t我也不确定),然后这种更新的方法也是第一次见,直接对区间进行操作,不用pushdown传下去,然后在查询的时候,去更新每个区间的值,涨姿势...
AC代码(线段树):
#include <iostream>
#include <cstdio>
#include <cstring>
#define lson l, mid, o << 1
#define rson mid + 1, r, o << 1 | 1
#define maxn 1000005
using namespace std;
int sum[maxn << 2],lsum[maxn << 2],rsum[maxn << 2];
int n,m;
char str[10];
void Build(int l,int r,int o){
lsum[o] = l;
rsum[o] = r;
sum[o] = 0;
if(l == r)return ;
int mid = (l + r) >> 1;
Build(lson);
Build(rson);
}
void Update(int L,int R,int ans,int o){
if(L <= lsum[o] && rsum[o] <= R){
sum[o] += ans;
return ;
}
int mid = (lsum[o] + rsum[o]) >> 1;
if(L > mid)Update(L,R,ans,o << 1 | 1);
else if(R <= mid)Update(L,R,ans,o << 1);
else{
Update(L,mid,ans,o<<1);
Update(mid+1,R,ans,o<<1|1);
}
}
int Query(int x,int o){
if(lsum[o] == x && rsum[o] == x){
return sum[o];
}
int mid = (lsum[o] + rsum[o]) >> 1;
int ans = sum[o];
if(x <= mid)ans += Query(x,o << 1);
else ans += Query(x,o << 1 | 1);
return ans;
}
int main()
{
scanf("%d%d",&m,&n);
Build(1,n,1);
while(m--){
scanf("%s",str);
if(str[0] == 'A'){
int x,y,z;
scanf("%d%d%d",&x,&y,&z);
Update(x,y,z,1);
}
else{
int x;
scanf("%d",&x);
printf("%d\n",Query(x,1));
}
}
return 0;
}
AC代码(树状数组):
#include <iostream>
#include <cstdio>
#include <cstring>
#define maxn 1000005
using namespace std;
int pre[maxn];
char str[10];
int n,m;
int lowbit(int x){
return x & (-x);
}
void Add(int x,int y){
for(int i=x;i<=n;i+=lowbit(i)){
pre[i] += y;
}
}
int Query(int x){
int sum = 0;
for(int i=x;i>=1;i-=lowbit(i)){
sum +=pre[i];
}
return sum;
}
int main()
{
scanf("%d%d",&m,&n);
while(m--){
scanf("%s",str);
if(str[0] == 'A'){
int x,y,z;
scanf("%d%d%d",&x,&y,&z);
Add(x, z);
Add(y + 1, -z);
}
else{
int x;
scanf("%d",&x);
printf("%d\n",Query(x));
}
}
return 0;
}