线段树模板

区间查询,区间修改

单点修改,单点查询

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
typedef long long ll;
using namespace std;
const int N=1e6;
ll sum[N<<2],b[N<<2];//b[]用作标记 
/*
	根据需求,数组的定义形式并不单一
	可以定义成 
	struct node
	{
		int data;
		int r;
		int l;	
	}sum[N];
	以便于数据的存储和记录 ,如查询区间的最大值与最小值时。
	
	另外,标记法并不适用于所有情况。 
	 在这种情况下,可以使用 剪枝 (即去掉一些不必要或重复的步骤) 
*/ 
void down(int id,int l)
{
	if(b[id])
	{
		b[id<<1]+=b[id];
		b[id<<1|1]+=b[id];
		//为什么 sum[id<<1]所加可能比sum[id<<1|1]大 
		/*
			跟我们建树方式有关 
			如下面build()函数部分所讲 
		*/ 
		sum[id<<1]+=b[id]*(l-(l>>1));
		sum[id<<1|1]+=b[id]*(l>>1);
		b[id]=0;
	}
}
void build(int id,int l,int r)
{
	if(l==r)
	{
		scanf("%lld",&sum[id]);
		return ;
	}
	int mid=(l+r)>>1;
	//在这种建树方式下,左子树的所被分配区间可能右子树的区间大,即: 
	//原始区间为奇数时:如1~9,左子树分配区间为1~5为 “五位 ”,右子树分配区间为6~9为 “四位 ” ,左区间大于右区间 
	//原始区间为偶数时:如1~8,左子树分配区间为1~4为 “五位 ”,右子树分配区间为5~8为 “四位 ”,左右区间一样大 
	// 
	build(id<<1,l,mid);
	build(id<<1|1,mid+1,r);
	sum[id]=sum[id<<1]+sum[id<<1|1];
}
void update(int t,int x,int y,int l,int r,int id)
{
	if(l>=x&&r<=y)//要修改区间覆盖现在所在区间,不必再往下进行查询,直接返回结果 
	{
		b[id]+=t;//b[]数组记录该id支配区间 各个数所要加的数 
		sum[id]+=(ll)t*(r-l+1);
		return;
	}
	down(id,r-l+1);
	int mid=(l+r)>>1;
	//在这里,为什么是x<=mid,y>mid呢,理由同上 ,即建树方式原因 
	if(x<=mid)	update(t,x,y,l,mid,id<<1);
	if(y>mid)	update(t,x,y,mid+1,r,id<<1|1);
	sum[id]=sum[id<<1]+sum[id<<1|1];
}
ll query(int x,int y,int l,int r,int id)
{
	if(l>=x&&r<=y)	return  sum[id];	
	down(id,r-l+1);
	int mid=(l+r)>>1;
	ll s=0;
	//在这里,为什么是x<=mid,y>mid呢,理由同上  ,即建树方式原因 
	if(x<=mid)   s+=query(x,y,l,mid,id<<1);
	if(y>mid)    s+=query(x,y,mid+1,r,id<<1|1);
	return s;
}
int main()
{
	int x,y,z,n,m;
	while(cin>>n>>m)
	{
		memset(sum,0,sizeof(sum));
		memset(b,0,sizeof(b));
		build(1,1,n);
		string s;
		while(m--)
		{
			cin>>s;
			if(s=="C")
			{
				scanf("%d%d%d",&x,&y,&z);
				update(z,x,y,1,n,1);
			}
			else
			{
				scanf("%d%d",&x,&y);
				printf("%lld\n",query(x,y,1,n,1));
			}
		}
	}
	return 0;
}

剪枝:

题意:1:区间查询

0:区间修改,即对区间内每一个数开方

#include<cstdio>
#include<cstring>
#include<cmath>
#include<iostream>
#include<algorithm>
using namespace std;
typedef long long ll;
const int N = 1e6+6;
ll a[N];
void build(int id, int L, int R)
{
	if(L == R)
	{
		scanf("%lld", &a[id]);
		return ;
	}
	int mid = (L + R) >> 1;
	build(id <<1, L, mid);
	build(id <<1|1, mid + 1, R);
	a[id]=a[id<<1]+a[id << 1 | 1];
}
void updata(int id, int L, int R, int l, int r)
{
	if(R-L+1 == a[id])
		return;
	if(L==R)
	{
		a[id] = sqrt((double)a[id]);
		return;
	}
	int mid = (L + R) >> 1;
	if(l <= mid) updata(id << 1, L, mid, l, r);
	if(r > mid) updata(id << 1 | 1, mid + 1, R, l, r);
	a[id] = a[id << 1] + a[id << 1 | 1];
}
ll query(int id, int L, int R, int l, int r)
{
	if(R-L+1 == a[id])
		return (min(R,r)-max(l,L)+1);
	if(L >=l&&R <= r)
		return a[id];
	ll s = 0;
	int mid = (L + R) >> 1;
	if(l <= mid) s += query(id << 1, L, mid, l, r);
	if(r > mid) s += query(id << 1 | 1, mid + 1, R, l, r);
	return s;
}
int main()
{
	int n, m,x, y,t,w=0;
	while(scanf("%d", &n) != EOF)
	{
		build(1, 1, n);
		scanf("%d", &m);
		printf("Case #%d:\n",++w);
		while(m--)
		{
			scanf("%d %d %d", &t, &x, &y);
			if(t)	printf("%lld\n", query(1, 1, n, min(x, y), max(x, y)));
			else	updata(1, 1, n, min(x, y), max(x, y));
		}
		puts("");
	}
	return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值