HDU1754 I Hate It (线段树单点修改+区间查询)


 
题目链接:传送门

解题思路:从题目中我们很明显知道只有两种操作,第一种是查询([A,B])范围内学生成绩的最大值,典型的RMQ,第二种操作是将A的成绩改为B,而不是改为B的成绩,请仔细体会。(当然样例都能看得出来),我们线段树只需要保存区间最大值,在updata和pushup两函数操作就行,最后注意多组输入,该题为线段树经典板子题。
 
Code:

#include<bits/stdc++.h>
using namespace std;

const int INF = 0x3f3f3f3f;
const int N = 2000005;
int n,m;
int a[N],tree[N << 2];

void push_up(int k) {
	tree[k] = max(tree[k<<1],tree[k<<1|1]);//把父节点的值更新为两子节点中的最大值
}
void build(int k, int l,int r) {
	if(l == r) {
		tree[k] = a[l];
	}
	else {
		int mid = l + ((r-l)>>1);
		build(k<<1,l,mid);
		build(k<<1|1,mid+1,r);
		push_up(k);
	}
}

void updata(int p,int v,int l,int r,int k) {
	if(l == r) {
		a[p] += v, tree[k] += v;
	}
	else {
		int mid = l + ((r-l)>>1);
		if(p <= mid) {
			updata(p,v,l,mid,k<<1);
		}
		else {
			updata(p,v,mid+1,r,k<<1|1);
		}
		push_up(k);
	}
}

int query(int L, int R,int l,int r,int k) {
	if(L <= l && R >= r) {
		return tree[k];
	}
	else {
		int ans = -INF;
		int mid = l+r >>1;
		if(L <= mid) {//如果查询区间在左边
			ans = max(ans,query(L,R,l,mid,k<<1));
		}
		if(R > mid) {//查询区间在右边
			ans = max(ans,query(L,R,mid+1,r,k<<1|1));
		}
		return ans;
	}
}
int main()
{
	while(~scanf("%d%d",&n,&m)) {
		for(int i = 1;i <= n; ++i) {
			scanf("%d",&a[i]);
		}
		build(1,1,n);
		char op;
		int l,r;
		while(m--) {
			cin>>op;
			if(op == 'Q') {
				scanf("%d%d",&l,&r);
				printf("%d
",query(l,r,1,n,1));
			}
			else if(op == 'U'){
				scanf("%d%d",&l,&r);
				updata(l,r-a[l],1,n,1);
			}
		}
	}
	return 0;
}
原文地址:https://www.cnblogs.com/Mangata/p/14290276.html