• 算法训练 操作格子


    时间限制:1.0s   内存限制:256.0MB

     
    问题描述

    有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<cstdio>
     2 #include<iostream>
     3 #define e tree[id]
     4 #define lson tree[id*2]
     5 #define rson tree[id*2+1]
     6 #define maxn 100005
     7 #define INT 100000000
     8 int A[maxn];
     9 struct Tree{
    10     int le,ri,v,s;
    11 }tree[4*maxn];
    12 int max(int a, int b){ return a>b?a:b; }
    13 void pushup(int id){ e.v = max(lson.v,rson.v); e.s = lson.s+rson.s; }
    14 void Build_tree(int id,int le,int ri)
    15 {
    16     e.le = le , e.ri = ri;
    17     if(le == ri){ e.v = A[le]; e.s = A[le];    return ; }
    18     int mid = (le+ri)/2;
    19     Build_tree(id*2,le,mid);
    20     Build_tree(id*2+1,mid+1,ri);
    21     pushup(id);
    22 }
    23 int Query1(int id,int x,int y)
    24 {
    25     int le=e.le,ri=e.ri;
    26     if(x<=le && ri<=y) return e.v;
    27     int mid=(le+ri)/2;
    28     int ret=-INT;
    29     if(x<=mid) ret=max(ret,Query1(id*2,x,y));
    30     if(y>mid) ret=max(ret,Query1(id*2+1,x,y));
    31     return ret;
    32 }
    33 long long  Query2(int id,int x,int y)
    34 {
    35     int le=e.le,ri=e.ri;
    36     if(x<=le && ri<=y) return e.s;
    37     int mid = (le+ri)/2;
    38     if(x<=mid && y>mid)  return Query2(id*2,x,y)+Query2(id*2+1,x,y);
    39     else if(x<=mid) return Query2(id*2,x,y);
    40     else return Query2(id*2+1,x,y);
    41 }
    42 void Update(int id,int k,int v)
    43 {
    44     int le=e.le,ri=e.ri;
    45     if(le == ri){ e.v=v ; e.s = v; return ;}
    46     int mid=(le+ri)/2;
    47     if(k<=mid) Update(id*2,k,v);
    48     else Update(id*2+1,k,v);
    49     pushup(id);
    50 }
    51 int main(void){
    52     int n,m,ans;
    53     scanf("%d%d",&n,&m);
    54     for(int i=1;i<=n;i++) scanf("%d",&A[i]);
    55     Build_tree(1,1,n);
    56     for(int i=1;i<=m;i++)
    57     {
    58         int p,x,y;
    59         scanf("%d%d%d",&p,&x,&y);
    60         switch(p)
    61         {
    62             case 1:
    63                 Update(1,x,y);
    64                 break;
    65             case 2:
    66                 ans=Query2(1,x,y);
    67                 printf("%lld
    ",ans);
    68                 break;
    69             case 3:    
    70                 ans=Query1(1,x,y);
    71                 printf("%d
    ",ans);
    72                 break;
    73         }
    74     }
    75 }
    //没有使用宏定义的方法
    #include<cstdio> #define maxn 100010 #define INT 100000000 using namespace std; int A[maxn]; struct Tree{ int le,ri,v,s; }tree[4*maxn]; int mymax(int a,int b){ return a>b?a:b;} void Pushup(int id) { tree[id].v=mymax(tree[id*2].v,tree[id*2+1].v); tree[id].s=tree[id*2].s+tree[id*2+1].s; return ; } void Update(int id,int k,int v) { int le=tree[id].le,ri=tree[id].ri; if(le==ri){ tree[id].v=v; tree[id].s=v; return ; } int mid=(le+ri)/2; if(k<=mid) Update(id*2,k,v); else Update(id*2+1,k,v); Pushup(id); } void Build_tree(int id,int x,int y) { tree[id].le=x,tree[id].ri=y; if(x==y){ tree[id].v=A[x]; tree[id].s=A[x]; return; } int mid=(x+y)/2; Build_tree(id*2,x,mid); Build_tree(id*2+1,mid+1,y); Pushup(id); } int Query_1(int id,int x,int y) { int le=tree[id].le,ri=tree[id].ri; if(x<=le && ri<=y) return tree[id].v; int mid = (le+ri)/2; int ret=-INT; if(x<=mid) ret=mymax(ret,Query_1(id*2,x,y)); if(y>mid) ret=mymax(ret,Query_1(id*2+1,x,y)); return ret; } long long Query_2(int id,int x,int y) { int le=tree[id].le,ri=tree[id].ri; if(x<=le && ri<=y) return tree[id].s; int mid=(le+ri)/2; if(x<=mid && y>mid) return Query_2(id*2,x,y)+Query_2(id*2+1,x,y); else if(x<=mid) return Query_2(id*2,x,y); else return Query_2(id*2+1,x,y); } int main(void) { int n,m,sum,max; scanf("%d%d",&n,&m); for(int i=1;i<=n;i++) scanf("%d",&A[i]); Build_tree(1,1,n); for(int i=1;i<=m;i++) { int p,x,y; scanf("%d%d%d",&p,&x,&y); switch(p) { case 1: Update(1,x,y); break; case 2: sum=Query_2(1,x,y); printf("%lld ",sum); break; case 3: max=Query_1(1,x,y); printf("%lld ",max); break; } } return 0; }
  • 相关阅读:
    过滤非GBK字符
    打印整数数字
    std::string 方法列表
    设计模式——单例模式(Singleton )
    编程之美二进制一的个数
    Jsoncpp试用指南
    GCC下宏扩展后的++i
    关于字节对齐的sizeof的讨论
    Notepad++ 更改和定制主题
    求子数组的最大和
  • 原文地址:https://www.cnblogs.com/zuimeiyujianni/p/8631365.html
Copyright © 2020-2023  润新知