I Hate It
Time Limit: 9000/3000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 48790 Accepted Submission(s): 19111
Problem Description
很多学校流行一种比较的习惯。老师们很喜欢询问,从某某到某某当中,分数最高的是多少。
这让很多学生很反感。
不管你喜不喜欢,现在需要你做的是,就是按照老师的要求,写一个程序,模拟老师的询问。当然,老师有时候需要更新某位同学的成绩。
这让很多学生很反感。
不管你喜不喜欢,现在需要你做的是,就是按照老师的要求,写一个程序,模拟老师的询问。当然,老师有时候需要更新某位同学的成绩。
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。
在每个测试的第一行,有两个正整数 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 9HintHuge input,the C function scanf() will work better than cin线段树入门 ,第一次学线段树 2015,7,28#include<stdio.h> #include<algorithm> #include<string.h> //#define max(a,b) ((a) > (b)? (a):(b))//max这样定义会超时,这么定义居然比库函数慢这么多 using namespace std; #define M 200010 struct node{ int l,r,val;//val表示该区间的最大值 }s[M*3];//数组要开大点来存左右子树 void build(int root,int lc,int rc) { s[root].l=lc; s[root].r=rc; if(lc==rc){ scanf("%d",&s[root].val);//左右重合时 return; } int mid=(lc+rc)>>1; build(root<<1,lc,mid); build(root<<1|1,mid+1,rc); s[root].val=max(s[root<<1].val,s[root<<1|1].val);//回溯时更新val的值 } void update(int root,int lc,int rc,int v) { if(s[root].l==lc && s[root].r==rc){ s[root].val=v;//如果 return; } int mid=(s[root].l+s[root].r)>>1; if(rc<=mid){//更新左子树 update(root<<1,lc,rc,v); } else if(lc>mid){//右子树 update(root<<1|1,lc,rc,v); } else{ update(root<<1,lc,mid,v); update(root<<1|1,mid+1,rc,v); } s[root].val=max(s[root<<1].val,s[root<<1|1].val); } int query(int u,int lc,int rc) { if(s[u].l==lc && s[u].r==rc) return s[u].val; int mid=(s[u].l+s[u].r)>>1; if(rc<=mid) return query(u<<1,lc,rc); else if(lc>mid) return query(u<<1|1,lc,rc); else return max(query(u<<1,lc,mid),query(u<<1|1,mid+1,rc)); } int main() { int n,m,c,b; char ch; while(~scanf("%d%d",&n,&m)){ build(1,1,n); while(m--){ getchar(); scanf("%c%d%d",&ch,&c,&b); if(ch=='Q'){ printf("%d\n",query(1,c,b)); } else{ update(1,c,c,b); } } } return 0; } /*还可以用树状数组来写这道题,树状数组相对于线段树代码简单,但是树状数组的局限性比较大 用线段树可以解决的问题用树状数组不一定能解决,能用树状数组的题,就一定可以用线段树解决, 一半树状数组存放的是一个区间的和,这里存的是一段区间的最大值*/ #include<stdio.h> #include<string.h> #include<algorithm> using namespace std; #define M 200010 int a[M],s[M];//a[]是原数组,s[]是树状数组 int n,m; int lowbit(int x) { return x&(-x);//移位函数 } void change(int i,int num)//更新每个树状数组 { a[i]=num; while(i<=n){ s[i]=max(s[i],num); i+=lowbit(i); } } int query(int l,int r)//查询找出最大值 { int ans=a[r]; while(l!=r){ r--; while(r-lowbit(r)>=l){ ans=max(s[r],ans); r-=lowbit(r); } ans=max(ans,a[r]); } return ans; } int main() { int x,y,i; char ch; while(~scanf("%d%d",&n,&m)){ memset(s,0,sizeof(s));//这一定要清0 for(i=1;i<=n;i++){ scanf("%d",&a[i]); change(i,a[i]); } while(m--){ getchar(); scanf("%c%d%d",&ch,&x,&y); if(ch=='U'){ change(x,y); } else{ printf("%d\n",query(x,y)); } } } return 0; }