这两道题,都是裸的线段树,并且线段树维护的都是区间和。放在一起整理一下,毕竟之前只是按照板子敲过。
HDU 1166----单点修改,区间查询
(小声哔哔:用区间来代替单点,一样能A的。毕竟原理都一样。在Add()函数和update( )函数那里,就是if-else的区别?)
//ac 单点修改
//HDU 1166 second
#include<iostream>
#include<algorithm>
#include<cstring>
#include<stdio.h>
#include<set>
#include<queue>
#include<stack>
using namespace std;
const int maxn=50005;
int num[maxn];
int tree[maxn<<2];
void pushup(int root)
{
tree[root]=tree[2*root]+tree[2*root+1];
}
void build(int root,int left,int right)
{
if(left==right)
{
tree[root]=num[left];
return ;
}
int mid=(left+right)/2;
build(root*2,left,mid);
build(root*2+1,mid+1,right);
pushup(root);
}
int Add(int root,int left,int right,int index,int addvalue)
{
if(left==right)
{
tree[root]+=addvalue;
return 0;
}
int mid=(left+right)/2;
if(index<=mid)
Add(root*2,left,mid,index,addvalue);
else
Add(root*2+1,mid+1,right,index,addvalue);
pushup(root);
}
int Query(int qleft,int qright,int cleft,int cright,int root)
{
if(qleft<=cleft && qright>=cright)
{
return tree[root];
}
int mid=(cleft+cright)/2;
int ans=0;
if(qleft<=mid)
ans+=Query(qleft,qright,cleft,mid,root*2);
if(qright>mid)
ans+=Query(qleft,qright,mid+1,cright,root*2+1);
return ans;
}
int main()
{
int t;
scanf("%d",&t);
int tcase=0;
while(t--)
{
printf("Case %d:\n",++tcase);
int n;
scanf("%d",&n);
for(int i=1;i<=n;i++)
scanf("%d",&num[i]);
build(1,1,n);
string s;
int i,j;
while(cin>>s)
{
if(s[0]=='E')
break;
if(s[0]=='A')
{
scanf("%d%d",&i,&j);
int index=i;
int addvalue=j;
Add(1,1,n,index,addvalue);
}
else if(s[0]=='S')
{
scanf("%d%d",&i,&j);
int index=i;
int addvalue=0-j;
Add(1,1,n,index,addvalue);
}
else if(s[0]=='Q')
{
scanf("%d%d",&i,&j);
int qleft=i;
int qright=j;
int res=Query(qleft,qright,1,n,1);
printf("%d\n",res);
}
}
}
}
POJ 3468----区间查询,修改
//POJ 3468 second
#include<iostream>
#include<algorithm>
#include<cstring>
#include<stdio.h>
#include<set>
#include<queue>
#include<stack>
using namespace std;
#define ll long long
const int maxn=1e5+5;
int num[maxn];
ll tree[maxn<<2];
ll mark[maxn<<2];
void pushup(int root)
{
tree[root]=tree[2*root]+tree[2*root+1];
}
void pushdown(int root,int ln,int rn)
{
if(mark[root])
{
tree[2*root]+=(ll)mark[root]*ln;
tree[2*root+1]+=(ll)mark[root]*rn;
mark[2*root]+=(ll)mark[root];
mark[2*root+1]+=(ll)mark[root];
mark[root]=0;
}
return;
}
void build(int root,int left,int right)
{
mark[root]=0;
if(left==right)
{
tree[root]=num[left];
return;
}
int mid=(left+right)/2;
build(2*root,left,mid);
build(2*root+1,mid+1,right);
pushup(root);
return;
}
ll Query(int qleft,int qright,int left,int right,int root)
{
if(left>=qleft && right<=qright)//当前区间[left,right] 在查询的区间之内。
return tree[root];
if(right<qleft || left>qright)//没有交集
return 0;
int mid=(left+right)/2;
pushdown(root,mid-left+1,right-mid);
ll ans=0;
if(mid>=qleft)//当前区间中点>区间左端点
ans+=Query(qleft,qright,left,mid,2*root);
if(mid<qright)
ans+=Query(qleft,qright,mid+1,right,2*root+1);
return ans;
}
void update(int uleft,int uright,int left,int right,int add,int root)
{
if(right<uleft || left>uright)
return;
if(left>=uleft && right<=uright)
{
tree[root]+=(right-left+1)*add;
mark[root]+=add;
return ;
}
int mid=(left+right)/2;
pushdown(root,mid-left+1,right-mid);
if(uleft<=mid)
update(uleft,uright,left,mid,add,2*root);
if(uright>mid)
update(uleft,uright,mid+1,right,add,2*root+1);
pushup(root);//区间更新之后的操作 ,易漏!
return ;
}
int main()
{
int n,q;
scanf("%d%d",&n,&q);
for(int i=1;i<=n;i++)
scanf("%d",&num[i]);
build(1,1,n);
while(q--)
{
char s[2];
scanf("%s",s);
if(s[0]=='Q')
{
int qright;
int qleft;
scanf("%d%d",&qleft,&qright);
ll res=Query(qleft,qright,1,n,1);
printf("%lld\n",res);
}
else if(s[0]=='C')
{
int uleft,uright;
int addmark;
scanf("%d%d%d",&uleft,&uright,&addmark);
update(uleft,uright,1,n,addmark,1);
}
}
}