hdu 1754 I Hate It

继续线段树水题。

求区间最大值,修改单个点。因为我还是采取的第一种建图方式,所以我修改单个点的话,比如修改1这个点,对应的我的区间应该是[1,2](你完全可以想象成左闭右开嘛)。

这样的话,每个节点设置一个值,保存这棵子树的最大值。

更新的时候,回溯的时候更新父节点即可。查询的时候,比如查询1 3段,在我的程序中对应的是0 3 段。只要查到被0 3 段完全包含的区间,那么这个区间的最大值就要返回,和另一个被0 3 完全包含的区间的最大值进行对比即可。

G++1000+MS。。看status我以为是我的线段树写的效率这么低!后来搜题解的时候,发现说是C++比较快,交C++,500ms,中等水平吧。

#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <iostream>
#include <cstring>
#include <string>
#include <algorithm>
#include <queue>
#include <stack>
#include <climits>
#define L(x) (x<<1)
#define R(x) (x<<1|1)
#define MID(x,y) ((x+y)>>1)
using namespace std;

const int MAX = 200010;
struct Tnode{ int scr,l,r;};
Tnode node[MAX*4];
int c[MAX];

void init()
{
	memset(node,0,sizeof(node));
}
void Build(int t,int l,int r)
{
	node[t].l = l;
	node[t].r = r;
	if( l == r-1 )
	{
		node[t].scr = c[l];
		return ;
	}
	int mid = MID(l,r);
	Build(L(t),l,mid);
	Build(R(t),mid,r);
	node[t].scr = max(node[L(t)].scr,node[R(t)].scr);
}

void Updata(int t,int l,int r,int scr)
{
	if( node[t].l == l && node[t].r == r )
	{
		node[t].scr = scr;
		return ;
	}
	int mid = MID(node[t].l,node[t].r);
	if( l >= mid )
		Updata(R(t),l,r,scr);
	else
		if( r <= mid )
			Updata(L(t),l,r,scr);
		else
		{
			Updata(L(t),l,mid,scr);
			Updata(R(t),mid,r,scr);
		}
	node[t].scr = max(node[L(t)].scr,node[R(t)].scr); // 父节点更新最大值 
}

int Compute(int t,int l,int r)
{
	if( node[t].l >= l && node[t].r <= r )
		return node[t].scr;
	int mid = MID(node[t].l,node[t].r);
	if( l >= mid )
		return Compute(R(t),l,r);
	else
		if( r <= mid )
			return Compute(L(t),l,r);
		else
			return max(Compute(L(t),l,mid),Compute(R(t),mid,r));
}

int main()
{
	int n,m,x,y;
	char s[2];
	while( ~scanf("%d%d",&n,&m) )
	{
		for(int i=0; i<n; i++)
			scanf("%d",&c[i]);
		init();
		Build(1,0,n+1);
		while( m-- )
		{
			scanf("%s%d%d",s,&x,&y);
			if( s[0] == 'U' )
				Updata(1,x-1,x,y);
			else
			{
				int ans = Compute(1,x-1,y);
				printf("%d\n",ans);
			}
		}
	}
return 0;
}


你可能感兴趣的:(hdu 1754 I Hate It)