题目描述:
问题描述 有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 <= 100000,0 <= 格子权值 <= 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 }
参考: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)