线段树最大数

Posted 行码棋

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了线段树最大数相关的知识,希望对你有一定的参考价值。

最大数


使用数据结构线段树来维护区间的最大值。

树中的每个节点都代表一个区间,同时记录了一个当前记录区间的最大值。

树的结点个数为区间长度的4倍:视最后一层叶子节点个数为 N N N,那么所有的节点数之和为 2 N − 1 2N-1 2N1,最后一层的节点可能还有分叉,节点个数最多为完全二叉树最后一层节点数目的2倍为 2 N 2N 2N,总的个数为 4 N − 1 4N-1 4N1

#include<bits/stdc++.h>
using namespace std;
const int N = 200005;

int m,p;
struct node
{
	int l,r;
	int v;
}tr[4*N];
//子节点向父节点上更新
void pushup(int u)
{
	tr[u].v = max(tr[u<<1].v,tr[u<<1|1].v);
}
//建树的操作,把每个节点的代表区间进行更新
void build(int u,int l,int r)
{
	tr[u] = {l,r};
	if(l==r) return ;//叶子节点时返回
	int mid = tr[u].l + tr[u].r >> 1;
	build(u<<1,l,mid),build(u<<1|1,mid+1,r);
}

int query(int u,int l,int r)
{
	//树中节点代表区间在查询区间之内直接返回树中记录的信息
	if(tr[u].l >= l && tr[u].r <= r) return tr[u].v;
	int mid = tr[u].l + tr[u].r >> 1;
	//记录最大值,注意初始化
	int v = 0;
	//区间左边l小于等于mid
	if(l <= mid) v = query(u<<1,l,r);
	//区间右边r大于mid,取最大值
	if(r > mid) v = max(v,query(u<<1|1,l,r));
	return v;
 } 
//单点修改操作,从节点u开始,将x位置的值修改为v
void modify(int u,int x,int v)
{
	//叶子节点直接修改
	if(tr[u].l==x && tr[u].r==x) tr[u].v = v;
	else 
	{
		int mid = tr[u].l + tr[u].r >> 1;
		if(x <= mid) modify(u<<1,x,v);
		else modify(u<<1|1,x,v);
		pushup(u);//修改完要向上更新记录的最大值
	}
}

int main()
{
	int n = 0;
	int last = 0;
	scanf("%d%d",&m,&p);
	build(1,1,m);
	int x;
	char s[2];
	while(m--)
	{
		scanf("%s%d",s,&x);
		if(s[0]=='Q')
		{
			last = query(1,n-x+1,n);
			printf("%d\\n",last);
		}
		else 
		{
			modify(1,n+1,(last+x)%p);
			n++;
		}
	}
	return 0;
 } 

以上是关于线段树最大数的主要内容,如果未能解决你的问题,请参考以下文章

线段树最大数

[JSOI2008]最大数 --线段树

线段树——最大数——洛谷——1198

P1198 最大数 线段树水题

线段树详解

[线段树]校OJ-JSOI2008最大数