最大值

TimeLimit: 1000MS  MemoryLimit: 65536 Kb

Totalsubmit: 161   Accepted: 4  

Description

Little Ming很喜欢训练自己的快速读能力,他最近找到一种新的考验并训练快速读能力的方法,在一行具有很多数的数列里任意指定某一段长度,从左往右扫视一遍后说出这段数列中的最大值,但他不想一直只使用一个数列,所以他请了他的好朋友,一位非常喜欢编程的学生,Little Little来帮忙在原数列上时不时的做一些修改,给他出题并检验他的答案是否正确。Little Little在做修改操作时会选取某个点修改它的值,在做出题操作时给出某一段的左右端点。

Input

本题目包含多组测试,请处理到文件结束。

在每个测试的第一行,有两个正整数 N 和 M (  0<N<=200000,0<M<5000 )

第二行包含N个整数,代表初始时数列中的数据。

接下来有M行。每一行有一个字符 C (只取'Q'或'S') ,和两个正整数A,B。

当C为'Q'的时候,表示这是一条出题操作,A,B为端点下标值,有可能A比B大。

当C为'S'的时候,表示这是一条修改操作,要求把第A个数修改为B。

Output

对于每一次出题操作,在一行里面输出最大的数。

相邻2组测试之间要有一个空行。

Sample Input

5 6

1 2 3 4 5

Q 1 5

S 3 6

Q 3 4

Q 4 5

S 2 9

Q 1 5

Sample Output

5
6
5
9



这是一道再基础不过的线段树题了,不多赘述,相见代码及注释。可先参阅:http://www.cppblog.com/hoolee/archive/2012/07/29/185531.html
细节:题目中说A可能大于B,要注意交换A、B。

  1#include<stdio.h>
  2#include<stdlib.h>
  3#include<string.h>
  4#define LEN 2000000
  5int N, M;
  6typedef struct MyNode
  7{
  8    int bg, ed;
  9    int max;
 10    int lf, rt;
 11}
MyNode;
 12MyNode A[LEN];//动态分配空间很耗时,先用数组A[]申请足够大的空间。
 13int count = 0;//记录A[]数组的使用情况,指向最后一个使用节点
 14int num[LEN];
 15int max(int a, int b)
 16{
 17    if(a > b)
 18        return a;
 19    return b;
 20}

 21void makeTree(int t)
 22{
 23    /*
 24    * t指向A[]节点的位置。
 25    * 建树过程为: 1.先有根节点,2.再建左右子树,3.然后修改根节点的子树指针
 26    */

 27    if(A[t].bg == A[t].ed)
 28    {
 29        A[t].max = num[A[t].bg];
 30        //A[t].lf = A[t].rt = 1;
 31        return;
 32    }

 33    int mid = (A[t].bg + A[t].ed) / 2;
 34    int lf = ++count;//开辟空间
 35    int rt = ++count;
 36    A[lf].bg = A[t].bg;
 37    A[lf].ed = mid;
 38    A[rt].bg = mid + 1;
 39    A[rt].ed = A[t].ed;
 40    makeTree(lf);
 41    makeTree(rt);
 42    A[t].lf = lf;
 43    A[t].rt = rt;
 44    A[t].max = max(A[lf].max, A[rt].max);
 45}

 46int query(int t, int bg, int ed)
 47{
 48    /*
 49        给定区间[bg, ed],查询区间的最大值,
 50        [bg, ed]区间与t节点代表的区间有四种关系:(令(A[t].bg + A[t].ed) / 2)
 51        1.他俩是同一个区间,查询成功,返回A[t].max
 52        2.bg <= mid, 接着查询t的左子树
 53        3.ed > min,接着查询t的右子树
 54        4.否认则,同时查询t的左右子树
 55    */

 56    if(A[t].bg == bg && A[t].ed == ed)
 57    {
 58        return A[t].max;
 59    }

 60    int mid = (A[t].bg + A[t].ed) / 2;
 61    if(ed <= mid)
 62    {
 63        return query(A[t].lf, bg, ed);
 64    }

 65    else if(bg > mid)
 66    {
 67        return query(A[t].rt, bg, ed);
 68    }

 69    else
 70    {
 71        return max(query(A[t].lf, bg, mid), query(A[t].rt, mid + 1, ed));
 72    }

 73        
 74}

 75void change(int ap, int p, int b)
 76{
 77    /*
 78        ap指向当前节点,p是要修改的位置,b为值
 79        分为3中情况:
 80        1.A[ap]为叶子节点,修改A[ap].max为b
 81        2.p在ap的左子树上,去左子树上查询
 82        3.p在ap的右子树上,去右子树上查询
 83    */

 84    if(A[ap].bg == A[ap].ed)
 85    {
 86        A[ap].max = b;
 87        return;
 88    }

 89    int mid = (A[ap].bg + A[ap].ed) / 2;
 90    if(p <= mid)
 91    {
 92        change(A[ap].lf, p, b);
 93    }

 94    else// p > mid
 95    {
 96        change(A[ap].rt, p, b);
 97    }

 98    A[ap].max = max(A[A[ap].lf].max, A[A[ap].rt].max);//子树的max改变了,也要修改父节点的max值
 99}

100int main()
101{
102    int i, j;
103    int spaceline = 0;
104    while(scanf("%d%d"&N, &M) == 2)
105    {
106        if(spaceline)
107        {
108            putchar(10);
109        }

110        else{
111            spaceline = 1;
112        }

113        
114        for(int i = 0; i < N; i++)
115            scanf("%d"&num[i]);
116        count = 0;
117        int t = ++count;
118        A[t].bg = 0;
119        A[t].ed = N - 1;
120        makeTree(t);
121        for(int i = 0; i < M; i++)
122        {
123            getchar();
124            char c = getchar();
125            int a, b;
126            scanf("%d%d"&a, &b);
127            if(c == 'Q')
128            {
129                if(a > b)
130                {
131                    int t2 = a;
132                    a = b;
133                    b = t2;
134                }

135                int rs = query(1, a - 1, b - 1);
136                printf("%d\n", rs);
137            }

138            else 
139            {
140                change(1, a - 1, b);
141            }

142            //printf("c=%c a=%d b=%d\n", c, a, b);
143        }

144    }

145    
146    //system("pause");
147    return 0;
148}

149



 其实这道题我先是用java写的,TLE,同样的思想,用C++写,410MS AC。下面是超时的java代码,可能是new太耗时了。

TLE的java代码



 

posted on 2013-04-28 18:47 小鼠标 阅读(239) 评论(0)  编辑 收藏 引用 所属分类: 数据结构

只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理


<2012年7月>
24252627282930
1234567
891011121314
15161718192021
22232425262728
2930311234

常用链接

随笔分类(111)

随笔档案(127)

friends

最新评论

  • 1. re: 线段树
  • 是这个样子的,所以在OJ有时候“卡住”了也不要太灰心,没准真的不是自己的原因呢。
    加油,祝你好运啦!
  • --小鼠标
  • 2. re: 线段树
  • 对于编程竞赛来说,Java所需时间一般为C/C++的两倍。合理的竞赛给Java的时间限制是给C/C++的两倍。
  • --伤心的笔
  • 3. re: poj1273--网络流
  • 过来看看你。
  • --achiberx
  • 4. re: (转)ubuntu11.10无法启动无线网络的解决方法
  • 膜拜大神。。查了一个下午资料终于在这里解决了问题。。神牛说的区域赛难道是ACM区域赛。。?
  • --Hang
  • 5. re: 快速排序、线性时间选择
  • 博主,谢谢你的文章。你的方法可以很好的处理分区基准在数组中重复的情况,书上的方法遇到这种输入会堆栈溢出。书上给出了解释但给的方法貌似不简洁。
  • --lsxqw2004

阅读排行榜