【Ybt OJ】[数据结构 第4章] 线段树 [前半章]

45 篇文章 0 订阅
30 篇文章 0 订阅

「 「 数据结构 」 」 4 4 4章 线段树 ( ( ( 3 3 3 ) ) )
目录:

A.求区间和
B.区间查改
C.小白逛公园

大家好 我是个菜鸡 我非常喜欢暴力数据结构 于是我用线段树过了这些题(

A . A. A. 例题 1 1 1 求区间和

在这里插入图片描述
在这里插入图片描述
洛谷 l i n k link link

分析:

那就树状数组 线段树过了呗 模板

CODE:

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<queue>
#include<vector>
#include<bitset>
#define Ctnue continue
//#pragma GCC optimize(2)
#define reg register
using namespace std;
typedef long long ll;
typedef double db;
typedef unsigned long long ull;
const int N=1e5+5;
int n,m;
ll sum[N*4];
void up(int x){
	sum[x]=sum[x<<1]+sum[x<<1|1];
}
void add(int x,int l,int r,int p,int val)
{
	if(l==r){
		sum[x]+=val;
		return;
	}
	int mid=(l+r)>>1;
	if(p<=mid) add(x<<1,l,mid,p,val);
	if(p>mid) add(x<<1|1,mid+1,r,p,val);
	up(x);
}
ll query(int x,int l,int r,int L,int R)
{
	if(L<=l&&r<=R) return sum[x];
	int mid=(l+r)>>1;
	ll ans=0;
	if(L<=mid) ans+=query(x<<1,l,mid,L,R);
	if(mid<R) ans+=query(x<<1|1,mid+1,r,L,R);
	return ans;
}
int main()
{
	scanf("%d%d",&n,&m);
	while(m--)
	{
		int kd,x,y;
		scanf("%d%d%d",&kd,&x,&y);
		if(kd==0) add(1,1,n,x,y);
		if(kd==1) printf("%lld\n",query(1,1,n,x,y));
	}
	
	return 0;
} 

B . B. B. 例题 2 2 2 区间查改

在这里插入图片描述
在这里插入图片描述
l i n k link link类似

分析:

线段树
在区间 [ a , b ] [a,b] [a,b]每个数 + x +x +x那就在修改线段树时 把当前区间值 + x × l e n [ a , b ] +x\times len[a,b] +x×len[a,b]即可

CODE:

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<queue>
#include<vector>
#include<bitset>
#define Ctnue continue
//#pragma GCC optimize(2)
#define reg register
using namespace std;
typedef long long ll;
typedef double db;
typedef unsigned long long ull;
const int N=1e6+5;
int n,q,a[N];
ll sum[N*4],lazy[N*4];
void up(int x){
	sum[x]=sum[x<<1]+sum[x<<1|1];
}
void down(int x,int l,int r)
{
	int mid=(l+r)>>1;
	sum[x<<1]+=lazy[x]*(mid-l+1);
	lazy[x<<1]+=lazy[x];
	sum[x<<1|1]+=lazy[x]*(r-(mid+1)+1);
	lazy[x<<1|1]+=lazy[x];
	lazy[x]=0;
}
void build(int x,int l,int r)
{
	if(l==r){
		sum[x]=a[l];
		return;
	}
	int mid=(l+r)>>1;
	build(x<<1,l,mid);
	build(x<<1|1,mid+1,r);
	up(x);
}
void add(int x,int l,int r,int L,int R,int val)
{
	if(L<=l&&r<=R){
		sum[x]+=1ll*val*(r-l+1);
		lazy[x]+=val;
		return;
	}
	down(x,l,r);
	int mid=(l+r)>>1;
	if(L<=mid) add(x<<1,l,mid,L,R,val);
	if(mid<R) add(x<<1|1,mid+1,r,L,R,val);
	up(x);
}
ll query(int x,int l,int r,int L,int R)
{
	if(L<=l&&r<=R) return sum[x];
	down(x,l,r);
	int mid=(l+r)>>1;
	ll ans=0;
	if(L<=mid) ans+=query(x<<1,l,mid,L,R);
	if(mid<R) ans+=query(x<<1|1,mid+1,r,L,R);
	return ans;
}
int main()
{
	scanf("%d%d",&n,&q);
	for(int i=1;i<=n;i++)
		scanf("%d",&a[i]);
	build(1,1,n);
	while(q--)
	{
		int kd;
		scanf("%d",&kd);
		if(kd==1){
			int x,y,z;
			scanf("%d%d%d",&x,&y,&z);
			add(1,1,n,x,y,z);
		} 
		if(kd==2){
			int x,y;
			scanf("%d%d",&x,&y);
			printf("%lld\n",query(1,1,n,x,y));
		}
	} 
	
	return 0;
} 

C . C. C. 例题 3 3 3 小白逛公园

在这里插入图片描述
在这里插入图片描述
洛谷 l i n k link link

分析:

与这道题也一样(

单点修改 区间最大子段和 那就用 O ( l o g n ) O(logn) O(logn)的线段树
v a l : [ L , R ] val:[L,R] val[L,R]的和
l s u m : lsum: lsum从左端点 L L L开始的最大子段和
r s u m : rsum: rsum从右端点 R R R开始的最大子段和
s u m : [ L , R ] sum:[L,R] sum[L,R]的最大子段和
那这样表示 就可以更新每种信息了

	tree[x].val=tree[x<<1].val+tree[x<<1|1].val;  //左区间和+右区间和
	tree[x].lsum=max(tree[x<<1].lsum,tree[x<<1].val+tree[x<<1|1].lsum);  //左区间最大子段和 或 左区间和+右区间左子段和
	tree[x].rsum=max(tree[x<<1|1].rsum,tree[x<<1|1].val+tree[x<<1].rsum);  //右区间最大子段和 或 右区间和+左区间右子段和
	tree[x].sum=max(max(tree[x<<1].sum,tree[x<<1|1].sum),tree[x<<1].rsum+tree[x<<1|1].lsum);  //左区间最大子段和 或 右区间最大子段和 或左区间右子段和+右区间左子段和

注意这里:

if(R<=mid) return query(x<<1,l,mid,L,R);  //只在左区间 就查询左区间
if(mid<L) return query(x<<1|1,mid+1,r,L,R);  //只在右区间 就查询右区间

与普通线段树不同 其他就正常更新了

CODE:

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<queue>
#include<vector>
#include<bitset>
#define Ctnue continue
//#pragma GCC optimize(2)
#define reg register
using namespace std;
typedef long long ll;
typedef double db;
typedef unsigned long long ull;
const int N=1e6+6;
struct Seg{
	ll lsum,rsum,sum,val;
}tree[4*N];
int n,m,a[N>>1]; 
void up(int x)
{
	tree[x].val=tree[x<<1].val+tree[x<<1|1].val;
	tree[x].lsum=max(tree[x<<1].lsum,tree[x<<1].val+tree[x<<1|1].lsum);
	tree[x].rsum=max(tree[x<<1|1].rsum,tree[x<<1|1].val+tree[x<<1].rsum);
	tree[x].sum=max(max(tree[x<<1].sum,tree[x<<1|1].sum),tree[x<<1].rsum+tree[x<<1|1].lsum);
}
void build(int x,int l,int r)
{
	if(l==r)
	{
		tree[x].lsum=tree[x].rsum=tree[x].sum=a[l];
		tree[x].val=a[l];
		return;
	}
	int mid=(l+r)>>1;
	build(x<<1,l,mid);
	build(x<<1|1,mid+1,r);
	up(x);
}
Seg query(int x,int l,int r,int L,int R)
{
	if(L<=l&&r<=R) return tree[x];
	int mid=(l+r)>>1;
	Seg ans,ansl,ansr;
	if(R<=mid) return query(x<<1,l,mid,L,R);
	if(mid<L) return query(x<<1|1,mid+1,r,L,R);
	ansl=query(x<<1,l,mid,L,R);
	ansr=query(x<<1|1,mid+1,r,L,R);
	ans.val=ansl.val+ansr.val;
	ans.lsum=max(ansl.lsum,ansl.val+ansr.lsum);
	ans.rsum=max(ansr.rsum,ansr.val+ansl.rsum);
	ans.sum=max(max(ansl.sum,ansr.sum),ansl.rsum+ansr.lsum);
	return ans;
}
void add(int x,int l,int r,int p,int value)
{
	if(l==r){
		tree[x].val=value;
		tree[x].lsum=tree[x].rsum=tree[x].sum=value;
		return;
	}
	int mid=(l+r)>>1;
	if(p<=mid) add(x<<1,l,mid,p,value);
	if(p>mid) add(x<<1|1,mid+1,r,p,value);
	up(x);
}
int main()
{
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++)
		scanf("%d",&a[i]);
	build(1,1,n);
	while(m--)
	{
		int kd,x,y;
		scanf("%d%d%d",&kd,&x,&y);
		if(kd==1)
		{
			if(x>y) swap(x,y);
			printf("%lld\n",query(1,1,n,x,y).sum);
		}
		if(kd==2) add(1,1,n,x,y);
	} 
	
	return 0;
} 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值