POJ - 4047 Garden 线段树 区间更新

本文介绍了一种使用线段树数据结构解决序列操作问题的方法,包括元素替换、元素交换及查询连续k个数的和的最大值。通过构建线段树并维护每个区间的最大值,可以高效地处理各种操作,特别是对于大规模数据集。

题目链接:点击查看

题意:

给出一个N个数的序列以及一个k(0<k<=n<=200000),m个操作p,x,y,其中

p=0:将x位置的数替换为y

p=1:将x y位置的数互换

p=2:  查询x-y位置区间连续k个数的和的最大值

题解:每个位置向前取k个数,作为这个位置的结果,线段树维护下每个区间的最大值即可,当改变一个位置p 的数时,把他所影响的区间(p,p+k-1)更新一下即可,查询(x,y)区间时,查询(x+k-1,y)的最大值即可

#include<iostream>
#include<cstdio>
#include<vector>
#include<map>
#include<algorithm>
using namespace std;
typedef long long ll;
const int N=200100;
struct node{
	int l,r;
	int laz;
	int maxx;
}tree[N<<2];
int sum[N],a[N];
int n,m,k;
void pushup(int cur)
{
	tree[cur].maxx=max(tree[cur<<1].maxx,tree[cur<<1|1].maxx);
}
void build(int l,int r,int cur)
{
	tree[cur].l=l;
	tree[cur].r=r;
	tree[cur].laz=0;
	if(l==r)
	{
		if(l<k) tree[cur].maxx=-1e9;
		else tree[cur].maxx=sum[l]-sum[l-k];
		return ;
	}
	int mid=(r+l)>>1;
	build(l,mid,cur<<1);
	build(mid+1,r,cur<<1|1);
	pushup(cur);
}
void pushdown(int cur)
{
	if(tree[cur].laz!=0)
	{
		tree[cur<<1|1].maxx+=tree[cur].laz;
		tree[cur<<1|1].laz+=tree[cur].laz;
		tree[cur<<1].maxx+=tree[cur].laz;
		tree[cur<<1].laz+=tree[cur].laz;
		tree[cur].laz=0; 
	}
}
void update(int pl,int pr,int cur,int val)
{
	if(pl<=tree[cur].l&&tree[cur].r<=pr)
	{
		
		tree[cur].maxx+=val;
		tree[cur].laz+=val;
		return;
	}	
	pushdown(cur);
	if(pl<=tree[cur<<1].r) update(pl,pr,cur<<1,val);
	if(pr>=tree[cur<<1|1].l) update(pl,pr,cur<<1|1,val);
	pushup(cur);
}
int query(int pl,int pr,int cur)
{
	if(pl<=tree[cur].l&&tree[cur].r<=pr)
	{
		return tree[cur].maxx;
	}
	int res=-1e9;
	pushdown(cur);
	if(pl<=tree[cur<<1].r) res=max(res,query(pl,pr,cur<<1));
	if(pr>=tree[cur<<1|1].l) res=max(res,query(pl,pr,cur<<1|1));
	return res;
}
int main()
{
	int T;
	int x,y,ll,rr,xx,yy;
	int op;
	scanf("%d",&T);
	while(T--)
	{
		scanf("%d%d%d",&n,&m,&k);
		for(int i=1;i<=n;i++)
		{
			scanf("%d",&a[i]);
			sum[i]=sum[i-1]+a[i];
		}
		build(1,n,1);
		while(m--)
		{
			scanf("%d%d%d",&op,&x,&y);
			if(op==0)
			{
				ll=max(k,x);
				rr=min(n,x+k-1);
				if(ll<=rr)update(ll,rr,1,y-a[x]);
				a[x]=y;
			}
			else if(op==1)
			{
				if(x>y) swap(x,y);
				ll=max(k,x);
				rr=min(n,x+k-1);
				if(ll<=rr) update(ll,rr,1,a[y]-a[x]);
					
				ll=max(k,y);
				rr=min(n,y+k-1);
				if(ll<=rr) update(ll,rr,1,a[x]-a[y]);
					
				swap(a[x],a[y]);

			}
			else
			{
				printf("%d\n",query(x+k-1,y,1));
			}
		}
	}
	return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值