Hduoj1754【线段树】

来源:互联网 发布:软件开发赚钱吗 编辑:程序博客网 时间:2024/06/08 12:48
/*I Hate ItTime Limit: 9000/3000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 41131    Accepted Submission(s): 16306Problem 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。Output对于每一次询问操作,在一行里面输出最高成绩。 Sample Input5 61 2 3 4 5Q 1 5U 3 6Q 3 4Q 4 5U 2 9Q 1 5 Sample Output5659HintHuge input,the C function scanf() will work better than cin  AuthorlinleSource2007省赛集训队练习赛(6)_linle专场  Recommendlcy   |   We have carefully selected several similar problems for you:  1698 1542 1394 2795 1540 */#include<stdio.h>struct node{int l, r, g;}node[800100];int fa[200022],  Max;void buildtree(int i, int left, int right)//建造一个空的二叉树 {node[i].l = left;node[i].r = right;node[i].g = 0;  //将树中的值全部初始化为0 if(left == right)//如果左右相等,说明已经到了二叉树的底部某个位置,可以存原始数组中的某个值 {fa[left] = i;//fa保存原始数组中的固定位置的值在二叉树中的位置 left即为原始数组中的第几个数i即为它在二叉树中的位置 return;}buildtree(i<<1, left, (left+right)/2);//分别两边建树 buildtree((i<<1)+1, (left+right)/2+1, right);}void update(int x)//将二叉树中x处的值更新为num {if(x == 1)  return;//编号为1已经更新到根节点 int f = x>>1;      //编号除2,求出父节点的编号 int a = node[f<<1].g;  //求出该父节点的两个儿子的值 int b = node[(f<<1)+1].g;node[f].g = a>b?a:b;//父节点的值更新为其中较大的值 update(f); //递归往上更新 }void query(int i, int x, int y){if(node[i].l == x && node[i].r == y)//如果区间找到,则比较最大值 {Max = Max > node[i].g?Max:node[i].g;return ;}i <<= 1;// 找出子节点 if(x <= node[i].r ){if(y <= node[i].r)//子区间在左子树中query(i, x, y);elsequery(i, x, node[i].r);//更改查询上限 } i++;if(y >= node[i].l){if(x >= node[i].l)//区间包含query(i, x, y);elsequery(i, node[i].l, y);//更改下限继续查询 }} int main(){int n, m, x, y, t;char ch;while(scanf("%d%d", &n, &m) != EOF){buildtree(1, 1, n);//以1号节点为根节点建立二叉树 for(int i = 1; i <= n; i++){scanf("%d", &t);node[fa[i]].g = t;//保存更改值 update(fa[i]);//更新二叉树 } while(m--){getchar();scanf("%c %d %d", &ch, &x, &y);if(ch == 'Q'){Max = 0;query(1, x,y);printf("%d\n",Max); }else{node[fa[x]].g = y;//更新线段树中的最底部的x处的值 update(fa[x]);//由于底部更新,则二叉树上面的全部更新 }}}}//树状数组超时代码 /*#include<stdio.h>#include<string.h>int a[200010], c[200010], n;void update(int x, int num, int n){while(x <= n){c[x] =  c[x]>num?c[x]:num;x += x&(-x);}}int query(int x, int y){int max = 0, j;j = y;while(j >= x){if(j - j&(-j) >= x-1)//如果此数涵盖区间在查询区间内  寻找最大值 {max = max>c[j]?max:c[j];j -= j&(-j);}else // 否则比较原数组中的单个值 {max = max>a[j]?max:a[j];j--;}} return max;}int main(){int i, j, m;while(scanf("%d%d", &n, &m) != EOF){memset(c, 0,sizeof(c));for(i = 1; i <= n; i++){scanf("%d", &a[i]);if(i&1)c[i] = a[i];elseupdate(i, a[i], n);}char ch;int max = 0;while(m--){getchar();scanf("%c %d %d", &ch, &i, &j);if(ch == 'U'){update(i, j, n);a[i] = j;}else{max = query(i,j);printf("%d\n", max);} }}return 0;}*/

题意:给出一序列数字,有两种操作,一时更改序列中的值,一个是查询一段区间内的最大值。输出查询时的最大值。

思路:标准的线段树模板题,代码中注释也比较详细了。

关键:需要弄清楚二叉树中的编号与左右区间的的关系,刚开始学容易弄混。

0 0
原创粉丝点击