WooKinson

  博客园 :: 首页 :: 博问 :: 闪存 :: 新随笔 :: 联系 :: 订阅 订阅 :: 管理 ::

题目描述:

问题描述
有n个格子,从左到右放成一排,编号为1-n。

共有m次操作,有3种操作类型:

1.修改一个格子的权值,

2.求连续一段格子权值和,

3.求连续一段格子的最大值。

对于每个2、3操作输出你所求出的结果。

输入格式
第一行2个整数n,m。

接下来一行n个整数表示n个格子的初始权值。

接下来m行,每行3个整数p,x,y,p表示操作类型,p=1时表示修改格子x的权值为y,p=2时表示求区间[x,y]内格子权值和,p=3时表示求区间[x,y]内格子最大的权值。

输出格式
有若干行,行数等于p=2或3的操作总数。

每行1个整数,对应了每个p=2或3操作的结果。

样例输入
4 3
1 2 3 4
2 1 3
1 4 3
3 1 4
样例输出
6
3
数据规模与约定
对于20%的数据n <= 100,m <= 200。

对于50%的数据n <= 5000,m <= 5000。

对于100%的数据1 <= n <= 100000,m <= 1000000 <= 格子权值 <= 10000
题目描述

 

代码如下:

  1 #include <stdio.h> 
  2 #define MAX(X,Y) (X)>(Y)?(X):(Y)
  3 
  4 struct node
  5 {
  6     int l,r,max,sum;
  7 }a[1000000];
  8 
  9 //初始化线段树 
 10 void init(int l,int r,int index)
 11 {    
 12     int mid;
 13     a[index].l = l;
 14     a[index].r = r;
 15     a[index].max = 0;
 16     a[index].sum = 0;
 17     if (l != r)
 18     {
 19         mid = (l+r)/2;
 20         init(l,mid,2*index);
 21         init(mid+1,r,2*index+1);
 22     }        
 23     return ;
 24 }
 25 
 26 //更新对应点的权值 
 27 void update(int old,int date,int index)
 28 {
 29     int mid;
 30     if (old>=a[index].l && old<=a[index].r)//更新点所在区间的信息 
 31     {
 32         a[index].max = date;//更新点所在区间的最大值 
 33         a[index].sum = date;//更新点所在区间的和 
 34     }
 35     if (a[index].l == a[index].r)
 36         return ;
 37     
 38     mid = (a[index].l + a[index].r)/2;
 39     if (old <= mid)
 40         update(old,date,2*index);
 41     else
 42         update(old,date,2*index+1);
 43     
 44     a[index].sum = a[2*index].sum + a[2*index+1].sum;
 45     a[index].max = MAX(a[2*index].max,a[2*index+1].max);    
 46     return ;
 47 }
 48 
 49 //查找区间的最大值 
 50 int find_max(int l,int r,int index)
 51 {
 52     int mid;
 53     if (l==a[index].l && r==a[index].r)
 54         return a[index].max;
 55         
 56     mid = (a[index].l + a[index].r)/2;
 57     if (l > mid)
 58         return find_max(l,r,2*index+1);
 59     else if (r <= mid)
 60         return find_max(l,r,2*index);
 61     else
 62         return MAX(find_max(l,mid,2*index),find_max(mid+1,r,2*index+1));
 63 }
 64 
 65 //求区间和 
 66 int find_sum(int l,int r,int index)
 67 {
 68     int mid;
 69     if (l==a[index].l && r==a[index].r)
 70         return a[index].sum;
 71         
 72     mid = (a[index].l + a[index].r)/2;
 73     
 74     if (l > mid)
 75         return find_sum(l,r,2*index+1);
 76     else if(r <= mid)
 77         return find_sum(l,r,2*index);
 78     else
 79         return find_sum(l,mid,2*index)+find_sum(mid+1,r,2*index+1);
 80 }
 81 
 82 int main(void)
 83 {
 84     int i;
 85     int n,m,date,x,y;
 86     scanf("%d%d",&n,&m);
 87     init(1,n,1);
 88     for (i=1 ; i<=n ; i ++)
 89     {
 90         scanf("%d",&date);
 91         update(i,date,1);//将i替换为date 
 92     }        
 93     
 94     while (m--)
 95     {
 96         scanf("%d%d%d",&date,&x,&y);
 97         switch(date)
 98         {
 99             case 1:
100                 update(x,y,1);break;//将x替换为y 
101             case 2:
102                 printf("%d\n",find_sum(x,y,1));break;//区间[x,y]的权值和 
103             case 3:
104                 printf("%d\n",find_max(x,y,1));break;//区间[x,y]的最大权值 
105             default:break;
106         }
107     }
108     
109     return 0;
110 }
C解法

参考:https://blog.csdn.net/libin56842/article/details/19909975

 

线段树了解:https://www.cnblogs.com/AC-King/p/7789013.html

解题思路:

    题目要求包括,1.权值替换;2.求区间和;求区间最大值

    普通数组查询方法对于2,3问题会出现超时,故使用线段树

    线段树类似二分查找,可大大缩短查找时间

 

 

线段树适用问题:

1.求区间数字和=左区间数字和+右区间数字和

2.最大公因数(GCD)=gcd(左区间gcd,右区间gcd)

3.最大值=max(左区间max,右区间max)

posted on 2018-12-21 10:16  WooKinson  阅读(240)  评论(0编辑  收藏  举报