蓝桥杯--算法练习:操作格子(线段树)

来源:互联网 发布:java泛型t 编辑:程序博客网 时间:2024/05/06 12:14
问题描述

有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。

我的思路:这个题刚开始我用数组直接做的 完了 得了五十分,看提示说用线段树 但是我用线段树写出来只得了40分 其余全是运行超时

      又去网上看,c++的代码输进去100分, 我跟他的代码一样样的改成java 50分 依旧是运行超时。。。。十分就相差在初始化的

      方式不同

这是 数组 版本的:


import java.util.Scanner;public class Main{public static void main(String[] args) {Scanner s=new Scanner(System.in);int n=s.nextInt();int m=s.nextInt();int arr[]=new int[n];int ope[][]=new int[m][3];for(int i=0;i<n;i++){arr[i]=s.nextInt();}for(int i=0;i<m;i++){ope[i][0]=s.nextInt();ope[i][1]=s.nextInt();ope[i][2]=s.nextInt();}for(int i=0;i<m;i++){if(ope[i][0]==1)arr[ope[i][1]-1]=ope[i][2];if(ope[i][0]==2){int x=0;for(int j=ope[i][1]-1;j<ope[i][2];j++)x+=arr[j];System.out.println(x);}if(ope[i][0]==3){int x=0;for(int j=ope[i][1]-1;j<ope[i][2];j++)x=Math.max(arr[j], x);System.out.println(x);}}}}
这是 我后来改的 线段树的版本:


import java.util.Scanner;public class Main{static Node tree[];static int arr[],ope[][],max,sum;public static void main(String[] args) {Scanner s=new Scanner(System.in);int n=s.nextInt();int m=s.nextInt();arr=new int[n];ope=new int[m][3];tree=new Node[300005];for(int i=0;i<n;i++){arr[i]=s.nextInt();}for(int i=0;i<tree.length;i++){// 我这因为我更新数据的方法 需要先初始化tree[i]=new Node();}getTree(1,1,n);int x=1;for(int i=0;i<m;i++){ope[i][0]=s.nextInt();ope[i][1]=s.nextInt();ope[i][2]=s.nextInt();}for(int i=0;i<m;i++){if(ope[i][0]==1)change(1,ope[i][1],ope[i][2]);if(ope[i][0]==2){findSum(1,ope[i][1],ope[i][2]);System.out.println(sum);sum=0;}if(ope[i][0]==3){findMax(1,ope[i][1],ope[i][2]);System.out.println(max);max=0;}}}public static void getTree(int i,int left,int right){tree[i].left=left;tree[i].right=right;if(left==right){tree[i].sum=arr[left-1];tree[i].max=arr[left-1];if(i%2==1)updata(i);return;}getTree(i*2,left,(left+right)/2);getTree(i*2+1,(left+right)/2+1,right);}public static void updata(int i){if(i==1)return;int fa=i/2;tree[fa].sum=tree[2*fa+1].sum+tree[2*fa].sum;tree[fa].max=(tree[2*fa].max>tree[2*fa+1].max)?tree[2*fa].max:tree[2*fa+1].max;updata(fa);}public static void change(int i,int n,int v){if(tree[i].left==tree[i].right){tree[i].sum=v;tree[i].max=v;updata(i);return;}if(tree[2*i].right>=n)change(2*i,n,v);else change(2*i+1,n,v);}public static void findMax(int i,int left,int right){if(tree[i].left==left&&tree[i].right==right){max=(tree[i].max>max)?tree[i].max:max;    return;}i=i<<1;if(tree[i].right>=left){if(tree[i].right>=right)findMax(i,left,right);else findMax(i,left,tree[i].right);}i+=1;if(tree[i].left<=right){if(tree[i].left<=left)findMax(i,left,right);else findMax(i,tree[i].left,right);}}public static void findSum(int i,int left,int right){if(tree[i].left==left&&tree[i].right==right){sum+=tree[i].sum;return;}i=i*2;if(tree[i].right>=left){if(tree[i].right>=right)findSum(i,left,right);else findSum(i,left,tree[i].right);}i+=1;if(tree[i].left<=right){if(tree[i].left<=left)findSum(i,left,right);else findSum(i,tree[i].left,right);}}}class Node{    int left;    int right;    int sum;    int max;}

这是 把那个c++的改成java以后 代码原封不动 移过来

import java.util.Scanner;public class 操作格子{static Node tree[];public static void main(String[] args) {Scanner s=new Scanner(System.in);int n=s.nextInt();int m=s.nextInt();tree=new Node[300005];getTree(1,1,n);for(int i=1;i<=n;i++){updata(1,i,s.nextInt());}while(m!=0){int a=s.nextInt();int b=s.nextInt();int c=s.nextInt();if(a==1)change(1,b,c);if(a==2){System.out.println(findSum(1,b,c));}if(a==3){System.out.println(findMax(1,b,c));}m--;}}public static void getTree(int i,int left,int right){tree[i]=new Node();tree[i].left=left;tree[i].right=right;//tree[i].sum=0;    //这里写上就跟上面那个结果一样 都是40分了//tree[i].max=0;if(left==right)return;getTree(i*2,left,(left+right)/2);getTree(i*2+1,(left+right)/2+1,right);}public static void updata(int i,int v,int num){tree[i].sum+=num;if(tree[i].max<num)tree[i].max=num;if(tree[i].left==tree[i].right)return;if(v<=(tree[i].left+tree[i].right)/2)updata(i*2,v,num);else updata(2*i+1,v,num);}public static void change(int i,int n,int v){if(n==tree[i].left&&n==tree[i].right){tree[i].sum=v;tree[i].max=v;return;}int mid=(tree[i].left+tree[i].right)/2;if(n<=mid)change(2*i,n,v);else change(2*i+1,n,v);tree[i].sum=tree[2*i].sum+tree[2*i+1].sum;tree[i].max=(tree[i*2].max>tree[2*i+1].max)?tree[i*2].max:tree[i*2+1].max;}public static int findMax(int i,int left,int right){if(tree[i].left==left&&tree[i].right==right){return tree[i].max;}int mid=(tree[i].left+tree[i].right)/2;if(right<=mid)return findMax(i*2,left,right);else if(left>mid) return findMax(2*i+1,left,right);else return (findMax(2*i,left,mid)>findMax(i*2+1,mid+1,right))?findMax(2*i,left,mid):findMax(i*2+1,mid+1,right);}public static int findSum(int i,int left,int right){if(tree[i].left==left&&tree[i].right==right){return tree[i].sum;}int mid=(tree[i].left+tree[i].right)/2;if(right<=mid)return findSum(i*2,left,right);else if(left>mid)return findSum(i*2+1,left,right);else return findSum(i*2,left,mid)+findSum(i*2+1,mid+1,right);}}class Node{    int left;    int right;    int sum;    int max;}

这是c++版本:100分。

#include <cstdio>#include <iostream>#include <cstring>#include <string>#include <cmath>#include <cstdlib>#include <algorithm>#include <queue>using namespace std;struct Line{int l, r;int sum, max;};Line arr[300005];void Build(int seat, int l, int r){arr[seat].l = l;arr[seat].r = r;arr[seat].sum = 0;arr[seat].max = 0;if(l == r)return;Build(seat * 2, l, (l + r) / 2);Build(seat * 2 + 1, (l + r) / 2 + 1, r);}void Insert(int seat, int v, int num){arr[seat].sum += num;if(arr[seat].max < num)arr[seat].max = num;if(arr[seat].l == arr[seat].r)return;if(v <= (arr[seat].l + arr[seat].r) / 2)Insert(seat * 2, v, num);elseInsert(seat * 2 + 1, v, num);}void Change(int seat, int v, int num){if(v == arr[seat].l && v == arr[seat].r){arr[seat].sum = num;arr[seat].max = num;return;}int middle = (arr[seat].l + arr[seat].r) / 2;if(v <= middle)Change(seat * 2, v, num);elseChange(seat * 2 + 1, v, num);arr[seat].sum = arr[seat * 2].sum + arr[seat * 2 + 1].sum;arr[seat].max = max(arr[seat * 2].max, arr[seat * 2 + 1].max);}int QuerySum(int seat, int l, int r){if(l == arr[seat].l && r == arr[seat].r)return arr[seat].sum;int middle = (arr[seat].l + arr[seat].r) / 2;if(r <= middle)return QuerySum(seat * 2, l, r);else if(l > middle)return QuerySum(seat * 2 + 1, l, r);else return QuerySum(seat * 2, l, middle) + QuerySum(seat * 2 + 1, middle + 1, r);}int QueryMax(int seat, int l, int r){if(l == arr[seat].l && r == arr[seat].r)return arr[seat].max;int middle = (arr[seat].l + arr[seat].r) / 2;if(r <= middle)return QueryMax(seat * 2, l, r);else if(l > middle)return QueryMax(seat * 2 + 1, l, r);else return max(QueryMax(seat * 2, l, middle), QueryMax(seat * 2 + 1, middle + 1, r));}int main(){int n, m, temp, v, a, b;scanf("%d%d", &n, &m);Build(1, 1, n);for(int i = 1; i <= n; i++){scanf("%d", &temp);Insert(1, i, temp);}while(m--){scanf("%d%d%d", &v, &a, &b);if(v == 1)Change(1, a, b);else if(v == 2)printf("%d\n", QuerySum(1, a, b));elseprintf("%d\n", QueryMax(1, a, b));}return 0;}