您的位置:首页 > 其它

HDU 1166 敌兵布阵 线段树入门_单点更新

2016-03-28 00:51 253 查看
线段树是连续区间动态更新的有力工具,由二叉树的特性可知其操作复杂度为 log(N)

本题是最最基础的线段树,但由此也算是入门了

线段树学习推荐优秀博客:点击打开链接

/* ***********************************************
Author        :angon
Created Time  :2016/3/27 20:00:05
File Name     :
************************************************ */

#include <stdio.h>
#include <string.h>
#include <iostream>
#include <algorithm>
#include <vector>
#include <queue>
#include <set>
#include <map>
#include <string>
#include <math.h>
#include <stdlib.h>
#include <time.h>
using namespace std;
const int maxn=50005;
int a[maxn];
struct node
{
int left,right;
int value;
};
node segTree[4*maxn];

void build(int i,int l,int r)
{
segTree[i].left=l;
segTree[i].right=r;
if(l==r)
{
segTree[i].value=a[l];
return ;
}
//递归构造左右子树
build(i<<1,l,(l+r)>>1);
build(i<<1|1,((l+r)>>1)+1,r);    // |1相当于+1
segTree[i].value=segTree[i<<1].value+segTree[i<<1|1].value;  //回溯时更新节点信息(由下至上)
}
void add(int i,int x,int y)  //单点更新信息,将y加到a[x]上,并更新被其影响的节点的值
{
if(segTree[i].left==segTree[i].right && segTree[i].left==x)  //找到所更新的节点
{
segTree[i].value+=y;
return ;
}
int mid=(segTree[i].left+segTree[i].right)>>1;
if(x<=mid) add(i<<1,x,y);
else       add(i<<1|1,x,y);
segTree[i].value=segTree[i<<1].value + segTree[i<<1|1].value; //回溯时更新节点信息
}

int ans;
void query(int i,int l,int r)  //查询信息,l,r为所有查询的区间
{
if(segTree[i].left==l && segTree[i].right==r)  //找到一次完全重合的区间
{
ans+=segTree[i].value;
return ;
}
//递归齐左右孩子
i<<=1;
if(l<=segTree[i].right)     //如果区间涉及左孩子,递归左孩子,下同
query(i,l,min(segTree[i].right,r));
i++;
if(r>=segTree[i].left)
query(i,max(l,segTree[i].left),r);

}

int main()
{
int T,n,ca=0;
scanf("%d",&T);
while(T--)
{
printf("Case %d:\n",++ca);
scanf("%d",&n);
for(int i=1;i<=n;i++)
scanf("%d",&a[i]);
build(1,1,n);
char s[6];
while(scanf("%s",s))
{
if(s[0]=='E') break;
int x,y;
scanf("%d%d",&x,&y);
if(s[0]=='A')
add(1,x,y);
else if(s[0]=='S')
add(1,x,-y);
else if(s[0]=='Q')
{
ans=0;
query(1,x,y);
printf("%d\n",ans);
}
}
}

return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: