线段树模板整理 HDU1166 POJ3468

这两道题,都是裸的线段树,并且线段树维护的都是区间和。放在一起整理一下,毕竟之前只是按照板子敲过。

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);
			}
		
		
	}
 }  
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值