UESTC 1425(线段树)

本文介绍了一种使用线段树进行区间更新和查询最长上升子串的算法实现。通过维护节点标记、最长上升子串等信息,在保证效率的同时解决了区间操作问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

该题有两种操作,a和q。

对于a,我们在每一个节点设计一个add标记。

对于q,首先我们在每个节点设计一个lcis代表该区间的最长上升子串。

显然,这个值和三个值有关。

1.左儿子的lcis

2.右儿子的lcis

3.左右儿子合并lcis

现在关键就是解决3,我们在每个节点设计四个值,left,right,lmost,rmost,

分别代表区间最左边的值,最右边的值,最左边的最长上升子串能到达的最右端,

最右边的最长上升子串能到达的最左端.那么3就能够解决了.只用判断lson的right

和rson的left的大小情况,如果可以合并,那么3求得的值就是rson.lmost-lson.rmost+1。

线段树功能:updata 成段更新,query 区间最值。


#include<cstdio>    
#include<iostream>    
#include<cstring>    
#include<algorithm>    
#include<cmath>    
using namespace std;    
#define lc l,m,index<<1    
#define rc m+1,r,index<<1|1    
#define N 100100    
struct node    
{    
	int add;    
	int lcis;    
	int left,right;    
	int lmost,rmost;    
}seg[N<<2];    
int n,q;    
void pushup(int index,int m)    
{    
	node& father=seg[index];    
	node& lson=seg[index<<1];    
	node& rson=seg[index<<1|1];    
	father.lcis=max(lson.lcis,rson.lcis);    
	father.left=lson.left;    
	father.right=rson.right;    
	father.lmost=lson.lmost;    
	father.rmost=rson.rmost;    
	if(lson.right<rson.left)    
	{    
		father.lcis=max(father.lcis,rson.lmost-lson.rmost+1);    
		if(father.lmost==m)father.lmost=rson.lmost;    
		if(father.rmost==m+1)father.rmost=lson.rmost;    
	}    
}    
void build(int l,int r,int index)    
{    
	int m=(l+r)>>1;    
	seg[index].add=0;    
	if(l==r)    
	{    
		scanf("%d",&seg[index].left);    
		seg[index].right=seg[index].left;    
		seg[index].lcis=1;    
		seg[index].lmost=seg[index].rmost=l;    
		return;    
	}    
	build(lc);    
	build(rc);    
	pushup(index,m);    
}    
void pushdown(int index)    
{    
	node& father=seg[index];    
	node& lson=seg[index<<1];    
	node& rson=seg[index<<1|1];    
	if(father.add)    
	{    
		lson.add+=father.add;    
		lson.left+=father.add;    
		lson.right+=father.add;    
		rson.add+=father.add;    
		rson.left+=father.add;    
		rson.right+=father.add;    
		father.add=0;    
	}    
}    
void updata(int L,int R,int num,int l,int r,int index)    
{    
	int m=(l+r)>>1;    
	if (L == l && r == R)    
	{    
		seg[index].add+=num;    
		seg[index].left+=num;    
		seg[index].right+=num;    
		return;    
	}    
	pushdown(index);    
	if(R<=m)updata(L,R,num,lc);    
	else if(L>m)updata(L,R,num,rc);  
	else  
	{  
		updata(L,m,num,lc);  
		updata(m+1,R,num,rc);  
	}  
	pushup(index,m);    
}    
int query(int L,int R,int l,int r,int index)    
{    
	int m=(l+r)>>1;    
	if (L == l && r == R)return seg[index].lcis;    
	pushdown(index);    
	if(R<=m)return query(L,R,lc);    
	else if(L>m)return query(L,R,rc);  
	else  
	{  
		int ret;    
		ret=max(query(L,m,lc),query(m+1,R,rc));    
		if(seg[index<<1].right<seg[index<<1|1].left)    
		{    
			ret=max(ret,min(seg[index<<1|1].lmost,R)-max(seg[index<<1].rmost,L)+1);    
		}    
		return ret;  
	}  
}    
int main()    
{    
	int t,tcase=1,a,b,c;    
	char op[2];    
	scanf("%d",&t);    
	while(t--)    
	{    
		printf("Case #%d:\n",tcase++);    
		scanf("%d%d",&n,&q);    
		build(1,n,1);    
		while(q--)    
		{    
			scanf("%s%d%d",op,&a,&b);    
			if(op[0]=='a')    
			{    
				scanf("%d",&c);    
				updata(a,b,c,1,n,1);    
			}    
			else    
			{    
				printf("%d\n",query(a,b,1,n,1));    
			}    
		}    
	}    
	return 0;    
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值