I Hate It(区间最大问题,线段树)

很多学校流行一种比较的习惯。老师们很喜欢询问,从某某到某某当中,分数最高的是多少。
这让很多学生很反感。

不管你喜不喜欢,现在需要你做的是,就是按照老师的要求,写一个程序,模拟老师的询问。当然,老师有时候需要更新某位同学的成绩。

Input本题目包含多组测试,请处理到文件结束。
在每个测试的第一行,有两个正整数 N 和 M ( 0<N<=200000,0<M<5000 ),分别代表学生的数目和操作的数目。
学生ID编号分别从1编到N。
第二行包含N个整数,代表这N个学生的初始成绩,其中第i个数代表ID为i的学生的成绩。
接下来有M行。每一行有一个字符 C (只取‘Q‘或‘U‘) ,和两个正整数A,B。
当C为‘Q‘的时候,表示这是一条询问操作,它询问ID从A到B(包括A,B)的学生当中,成绩最高的是多少。
当C为‘U‘的时候,表示这是一条更新操作,要求把ID为A的学生的成绩更改为B。
Output对于每一次询问操作,在一行里面输出最高成绩。Sample Input

5 6
1 2 3 4 5
Q 1 5
U 3 6
Q 3 4
Q 4 5
U 2 9
Q 1 5

Sample Output

5
6
5
9
代码如下:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll N=2e5+7;
int a[N];
int  ans=0,n,q;
struct node{
	int l,r;
	int mx;
}tree[N*4]; //用结构体储存树
void pushup(int now){
	tree[now].mx=max(tree[now<<1].mx,tree[now<<1|1].mx);
}//向上更新
void buildtree(int now,int l,int r){
	tree[now].l=l;
	tree[now].r=r;
	if(l==r){
		tree[now].mx=a[l];
		return ;
	}
	int mid=(l+r)>>1;
	buildtree(now<<1,l,mid);
	buildtree(now<<1|1,mid+1,r);
	pushup(now);

}//建树
void update(int now,int pos,int v){
	int L=tree[now].l,R=tree[now].r;
	if(L==R){
		tree[now].mx=v;
		return;
	}//找到所要修改的点后则返回
	int mid=(L+R)>>1;
	if(pos<=mid)update(now<<1,pos,v);//修改点在左儿子那边,向左儿子继续找
	else update(now<<1|1,pos,v);//修改点在右儿子那边
	pushup(now);
}
void query(int now,int l,int r){
	int L=tree[now].l,R=tree[now].r;
	if(L==l&&R==r){
		ans=max(ans,tree[now].mx);
		return;
	}//查询区间和现区间刚好吻合
	int mid=(L+R)>>1;
	if(r<=mid)query(now<<1,l,r);//查询区间靠左儿子那边
	else if(l>mid)query(now<<1|1,l,r);//查询区间靠右儿子那边
	else{
		query(now<<1,l,mid);
		query(now<<1|1,mid+1,r);
	}//查询区间与左儿子和右儿子都有交集
}
int main(){
	while(scanf("%d%d",&n,&q)!=EOF){
		for(int i=1;i<=n;i++)scanf("%d",&a[i]);
		buildtree(1,1,n);
		while(q--){
			char str[5];
			int x,y;
			scanf("%s%d%d",str,&x,&y);
			if(str[0]==‘Q‘){
				ans=0;
				query(1,x,y);
				printf("%d\n",ans);
			}
			else
				update(1,x,y);
		}
	}
	return 0;
}

原文地址:https://www.cnblogs.com/chuliyou/p/12541929.html

时间: 2024-08-02 09:45:51

I Hate It(区间最大问题,线段树)的相关文章

FOJ 2171 防守阵地 II 区间求和区间查询 线段树

题目链接:http://acm.fzu.edu.cn/problem.php?pid=2171 题意: 给定n长序列,常数m,q个询问 对于每个询问x 1.求[x, x+m-1] 区间和 2.[x,x+m-1]区间的所有元素-1 线段树裸题,不知为何全用longlong会re,只能改成部分longlong #include<stdio.h> #include<string.h> #define ll long long #define LL int #define L(x) (x*

【BZOJ4653】[Noi2016]区间 双指针法+线段树

[BZOJ4653][Noi2016]区间 Description 在数轴上有 n个闭区间 [l1,r1],[l2,r2],...,[ln,rn].现在要从中选出 m 个区间,使得这 m个区间共同包含至少一个位置.换句话说,就是使得存在一个 x,使得对于每一个被选中的区间 [li,ri],都有 li≤x≤ri. 对于一个合法的选取方案,它的花费为被选中的最长区间长度减去被选中的最短区间长度.区间 [li,ri] 的长度定义为 ri−li,即等于它的右端点的值减去左端点的值. 求所有合法方案中最小

线段树———区间最大数(线段树入门)

线段树初级(区间最大数) 其实就是对树进行二分查找      (当然需要结合递归) 思路: 要从区间中找到最大数,当然可以暴力求解,但你不怕超时吗??? so      让我们来学习线段树吧!!!!!!!!!!!!!!! 在c++里下面这个代码是极快的(哇咔咔!!!) 题目描述 给出一列数共N个,将其从1到N编号,进行M次查询[X, Y](X<=Y),给出第X个数到第Y个数间最大的数. 输入 一组测试数据,第一行输入N,M(1<=N, M<=10^5),第二行N个数:之后M行,每行分别为

线段树之区间最大数(线段树入门)

线段树初级(区间最大数) 其实就是对树进行二分查找      (当然需要结合递归) 思路: 要从区间中找到最大数,当然可以暴力求解,但你不怕超时吗??? so      让我们来学习线段树吧!!!!!!!!!!!!!!! #include <iostream> #include <cstdio> #include <cstring> using namespace std; #define maxn 100010 struct N {     int l, r, max

【BZOJ3878】【Ahoi2014】奇怪的计算器 维护区间性质。线段树

广告: #include <stdio.h> int main() { puts("转载请注明出处[vmurder]谢谢"); puts("网址:blog.csdn.net/vmurder/article/details/44037685"); } 题解: 先排序然后插入线段树 用线段树每次对全区间进行操作. 然后维护哪些段区间溢出了,对这段区间进行赋值. 溢出处理: 一个区间的左端点大于最大值,或者右端点小于最小值 那么这个区间就该被覆盖. 覆盖,加特

Benelux Algorithm Programming Contest 2014 Final ACM-ICPC Asia Training League 暑假第一阶段第二场 E. Excellent Engineers-单点更新、区间最值-线段树 G. Growling Gears I. Interesting Integers-类似斐波那契数列-递推思维题

先写这几道题,比赛的时候有事就只签了个到. E. Excellent Engineers 传送门: 这个题的意思就是如果一个人的r1,r2,r3中的某一个比已存在的人中的小,就把这个人添加到名单中. 因为是3个变量,所以按其中一个变量进行sort排序,然后,剩下的两个变量,一个当位置pos,一个当值val,通过线段树的单点更新和区间最值操作,就可以把名单确定. 代码: 1 //E-线段树 2 #include<iostream> 3 #include<cstdio> 4 #incl

HDU 3308 LCIS (经典区间合并)【线段树】

<题目链接> 题目大意: 给你一段序列,对其进行两种操作,一是修改某个序号的点的值:二是查询某个区间的LCIS(最长上升子序列). 解题分析: 线段树区间合并的典型例题,用求某个区间的LCIS时,需要比较三个值,一是左区间的LCIS,二是右区间的LCIS,三是左右子区间合并的LCIS.最重要的是第三点如何实现,实现第三点需要维护一个最长后缀上升子序列和最长前缀上升子序列. #include <cstdio> #include <cstring> #include <

HDU 1540 Tunnel Warfare(区间合并)【线段树】

<题目链接> 题目大意: 题意:一个长度为n的线段,下面m个操作 D x 表示将单元x毁掉 R  表示修复最后毁坏的那个单元 Q x  询问这个单元以及它周围有多少个连续的单元,如果它本身已经被毁坏了就是0. 解题分析: 用线段树求指定点所在的最长连续区间,属于线段树区间合并类型的题,线段树的每个节点需要维护三个值,分别是对应区间的最长连续区间长度,对应区间最长连续区间前缀,对应区间最长连续后缀,然后就是在每次update之后都维护一下这三个值就行.并且注意一下query 时的操作. 1 #i

HDU 4553 约会安排 (区间合并)【线段树】

<题目链接> 寒假来了,又到了小明和女神们约会的季节.  小明虽为屌丝级码农,但非常活跃,女神们常常在小明网上的大段发言后热情回复"呵呵",所以,小明的最爱就是和女神们约会.与此同时,也有很多基友找他开黑,由于数量实在过于巨大,怎么安排时间便成了小明的一大心事.  我们已知小明一共有T的空闲时间,期间会有很多女神或者基友来找小明.  作为一个操作系统曾经怒考71分的大神,小明想到了一个算法,即"首次适应算法",根据操作系统课本的描述,就是找一段最靠前的符

HDU 5700 区间交(线段树)

题目链接 区间交 1 #include <bits/stdc++.h> 2 3 using namespace std; 4 5 #define rep(i, a, b) for (int i(a); i <= (b); ++i) 6 #define dec(i, a, b) for (int i(a); i >= (b); --i) 7 8 #define lson i << 1, L, mid 9 #define rson i << 1 | 1, mid