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
Hint
Huge input,the C function scanf() will work better than cin
思路: 单源点更新,求最大值
代码
#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<iostream>
#include<math.h>
#include<queue>
#include<stack>
#include<map>
#include<vector>
#include<set>
#define LL long long
#define M 5000000 // 定义的大
#define inf 0x3f3f3f3f
#define mod 100009
#define ll o<<1
#define rr o<<1|1
#define lson o<<1,l,mid // 左子节点
#define rson o<<1|1,mid+1,r // 右子节点 (易错写)
using namespace std;
struct Tree
{
int l,r; // 一个节点 所代表的 区间左值和区间右值
int max; // 一个节点 所代表的区间 的 权值 这里是 最大值
} tree[M<<2]; // 结构体 数组 的大小 注意
void pushup(int o)
{
tree[o].max = max(tree[ll].max,tree[rr].max); // 更新 非子叶 节点
}
void build(int o,int l, int r) //构建 树
{
tree[o].l=l; // 获取 当前节点的 区间左值
tree[o].r=r; // 获取 当前节点的 区间右值
if( l== r) // 如果 区间左值==区间右值 则 说明到了 子叶节点 可以从键盘获取 权值
{
int a;scanf("%d",&a);
tree[o].max=a;
return ; // 不能少 ,判出的标志
}
int mid=( l+ r)>>1;
build(lson); // 构建 左节点
build(rson); // 构建 右节点
pushup(o); // 每个非 子叶 节点都会进行更新
}
void update(int o,int pos,int val) // 更新操作
{
if(tree[o].l==tree[o].r)
{
tree[o].max=val;
return ; // 判出的标志 勿忘
}
int mid=(tree[o].l+tree[o].r)>>1;
if(pos<=mid) update(ll,pos,val); // 判定 要更新值的 位置 到底是在 左节点还是 右节点
else update(rr,pos,val);
pushup(o); // 每个非 子叶 节点都会进行更新
}
int query(int o,int l,int r) //查 询操作 ===》 是从根节点 开始 寻找的
{
if(l<=tree[o].l&&r>=tree[o].r) // 完全包含 才可以 判出
return tree[o].max;
int mid=(tree[o].l+tree[o].r)>>1;
// 由于 要查询的 区间不同 可能导致的 三种不同的 方向
if(r<=mid) query(ll,l,r); // 可以判定 pos 一定在当前节点的 左子树
else if(l>mid ) query(rr,l,r); // 可以判定 pos 一定在当前节点 的右子树
else
return max(query(ll,l,mid),query(rr,mid+1,r)); // 区间是在 左子树和右子树的中间,要找到其中的最大值
}
int main()
{
int n,m;
while(~scanf("%d%d",&n,&m))
{
build(1,1,n); // 定义 树 的起始
while(m--)
{
char c[2];int x,y;
scanf("%s%d%d",c,&x,&y);
if(c[0]=='Q') printf("%d\n",query(1,x,y));
else
update(1,x,y);
}
}
return 0;
}
不用结构体的线段树,代码
#include<bits/stdc++.h>
using namespace std;
#define LL long long
#define fread() freopen("in.txt","r",stdin)
#define fwrite() freopen("out.txt","w",stdout)
#define CLOSE() ios_base::sync_with_stdio(false)
const int MAXN = 200000+10;
const int MAXM = 1e6;
const int mod = 1e9+7;
const int inf = 0x3f3f3f3f;
int Max[MAXN<<2];
void Up(int o){
Max[o]=max(Max[o<<1],Max[o<<1|1]);
}
void Build(int o,int le,int ri){
if(le==ri){
scanf("%d",&Max[o]);
return ;
}
int mid=(le+ri)>>1;
Build(o<<1,le,mid);
Build(o<<1|1,mid+1,ri);
Up(o) ;
}
void UpDate(int o,int le,int ri,int p,int val){
if(le==ri){
Max[o]=val;
return ;
}
int mid=(le+ri)>>1;
if(p<=mid) UpDate(o<<1,le,mid,p,val);
if(p>mid) UpDate(o<<1|1,mid+1,ri,p,val);
Up(o);
}
int Query(int o,int le,int ri,int L,int R){
if(L<=le&&ri<=R){
return Max[o];
}
int mid=(le+ri)>>1;
int ans=0;
if(L<=mid) ans=max(ans,Query(o<<1,le,mid,L,R));
if(R>mid) ans=max(ans,Query(o<<1|1,mid+1,ri,L,R));
return ans;
}
int main(){
CLOSE();
// fread();
// fwrite();
int n,m;
while(scanf("%d%d",&n,&m)!=EOF){
Build(1,1,n);
char op[2];int a,b;
while(m--){
scanf("%s %d %d",op,&a,&b);
if(op[0]=='Q')
printf("%d\n",Query(1,1,n,a,b));
else UpDate(1,1,n,a,b);
}
}
return 0;
}
分块 :
代码
#include<bits/stdc++.h>
using namespace std;
#define LL long long
#define ULL unsigned long long
const int N = 2e5+11;
const int M = 1e6+11;
const int inf =0x3f3f3f3f;
const int mod = 1e9+7;
const int inff = 0x3f3f3f3f3f3f3f3f;
/*-------------------------------------*/
int mx[1000]; int a[N]; int B; // 区间最值,单点更新 .
int Query(int l,int r){
int ans=-1;
for(int i=l;(i/B)==(l/B)&&i<=r;i++) ans=max(ans,a[i]);
if(l/B!=r/B) for(int i=r;(i/B)==(r/B);i--) ans=max(ans,a[i]);
for(int i=(l/B)+1;i<(r/B);i++) ans=max(ans,mx[i]);
return ans;
}
void UpDate(int pos,int val){
a[pos]=val; mx[pos/B]=-1;
for(int j=pos/B*B;j/B == pos/B;j++)
mx[pos/B]=max(mx[pos/B],a[j]);
}
int main(){
int n,m; a[0]=-1;
while(scanf("%d%d",&n,&m)!=EOF){
B=(int)floor(sqrt(n*1.0));
memset(mx,-1,sizeof(mx));
for(int i=1;i<=n;i++) {
scanf("%d",&a[i]);
mx[i/B]=max(mx[i/B],a[i]);
}
while(m--){
char op[5]; int a,b;
scanf("%s %d %d",op,&a,&b);
if(op[0]=='Q') printf("%d\n",Query(a,b));
else UpDate(a,b);
}
}
return 0;
}