算法训练 操作格子

算法训练 操作格子  
时间限制:1.0s   内存限制:256.0MB
   
锦囊1
使用线段树。
锦囊2
线段树的每个结点记录下这一段区间所有数的和以及最大值即可。
锦囊3
问题描述

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

解析:利用线段树解决问题

 

#include<stdio.h>
#include<stdlib.h>
#define N 100000
int w[N+10];
typedef struct Node{
        struct Node *lc,*rc;
        int left,right;//左右区间端点
        int max;//对应区间最大值
        int sum;//对应区间元素和
        }tree,*Interval_tree;
void Build(Interval_tree &T,int left,int right)
{
     //构建线段树 
     int mid;
     T=(Interval_tree)malloc(sizeof(tree));
     T->lc=NULL;
     T->rc=NULL;
     T->left=left;
     T->right=right;
     if(left==right)
     {
        T->sum=w[left];
        T->max=w[left];
        return ;//递归出口
     }//if
     mid=(left+right)>>1;
     Build(T->lc,left,mid);
     Build(T->rc,mid+1,right);
     T->sum=T->lc->sum+T->rc->sum;
     T->max=T->lc->max>T->rc->max?T->lc->max:T->rc->max;
}
int query_sum(Interval_tree &T,int x,int y)
{
        int mid=(T->left+T->right)>>1;
        if(T->left==x&&T->right==y)
        {
           return T->sum;
        }
        if(mid+1<=x)
           return query_sum(T->rc,x,y);
        if(mid>=y)
           return query_sum(T->lc,x,y);
           return query_sum(T->lc,x,mid)+query_sum(T->rc,mid+1,y);
}// 
int  query_max(Interval_tree &T,int x,int y)
{
     int mid;
     if(T->left==x&&T->right==y)
     return T->max;
     mid=(T->left+T->right)>>1;
     if(mid+1<=x)
     return query_max(T->rc,x,y);
     if(mid>=y)
     return query_max(T->lc,x,y);
     return query_max(T->lc,x,mid)>query_max(T->rc,mid+1,y)?query_max(T->lc,x,mid):query_max(T->rc,mid+1,y);
}//
void update(Interval_tree &T,int x,int y)
{
     int mid;
     if(T->left==x&&T->right==x)
     {
        T->sum=y;
        T->max=y;
        return;
     }
     mid=(T->left+T->right)>>1;
     if(x<=mid)
     {
        update(T->lc,x,y);
     }
     if(x>=mid+1)
     {
        update(T->rc,x,y);
     }
     T->sum=T->lc->sum+T->rc->sum;
     T->max=T->lc->max>T->rc->max?T->lc->max:T->rc->max;
     
}
        
void ftree(Interval_tree &T)
{
     if(T!=NULL)
     {
         if(T->lc!=NULL)
         free(T->lc);
         if(T->rc!=NULL)
         free(T->rc);
         free(T);
     }
}              
int main()
{
    int n,m,i;
    int a,x,y;
    Interval_tree T;
    scanf("%d%d",&n,&m);
    for(i=1;i<=n;i++)
    {
       scanf("%d",&w[i]);
    }//for
    Build(T,1,n);
    while(m--)
    {
       scanf("%d%d%d",&a,&x,&y);
       switch(a){
                 case 1:
                      update(T,x,y);//修改格子x的权值为y
                      break;
                 case 2:
                      printf("%d\n",query_sum(T,x,y));//求区间[x,y]内格子权值和
                      break;
                 case 3:
                      printf("%d\n",query_max(T,x,y));//求区间[x,y]内格子最大的权值
                      break;
                 }//swith
       }//whlie
       ftree(T);//释放空间
    //system("pause");
       return 0;
} 


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值