操作格子

         操作格子

问题描述

有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>  
//定义结构体:线段树   
typedef struct node  
{  
    int max, sum;         //统计线段树的最大值、和   
    int left,right;       //线段树区间的左右值   
    struct node *lchild;  //左子树   
    struct node *rchild;  //右子树   
}XNode;  
//返回最大值  
int maxValue(int max, int temp)  
{  
    if (temp > max)  
        max = temp;  
    return max;           //返回最大值   
}   
//创建线段树  
XNode *CreateXTree(int left, int right) //传进区间左右值   
{  
    XNode *xTree = (XNode *)malloc(sizeof(XNode));  
    xTree->left = left;    //给左端赋值   
    xTree->right = right;  //给右端赋值  
    xTree->max = 0;        //线段树:结点维护内容  
    xTree->sum = 0;   
    xTree->lchild = NULL;   //子树初始化 置空   
    xTree->rchild = NULL;   //置空  
    if (right != left)      //right != left  元区间   
    {  
        int mid = (left+right)/2;   //区间中点   
        xTree->lchild = CreateXTree(left, mid);  //创建左子树  
        xTree->rchild = CreateXTree(mid+1, right); //创建右子树   
    }   
    return xTree;  
}   
//插入一条线段  
void Insert(XNode *xTree, int point, int value)  
{  
    xTree->sum += value;            //搜索树时,经过某区间 统计   
    xTree->max = maxValue(xTree->max,value);//maxValue返回最大值   
    if (xTree->left == xTree->right)//找到该线段   
        return;  
    else  
    {  
        if (point <= (xTree->left + xTree->right)/2)   
            Insert(xTree->lchild,point,value);//左搜索   
        else  
            Insert(xTree->rchild,point,value);//右搜索   
    }  
    return;  
}  
//1.修改格子权值  
void Modify(XNode *xTree, int point, int value)  
{  
    if (xTree->left == point && xTree->right == point) //找到该结点,修改   
    {  
        xTree->max = value;//修改最大值   
        xTree->sum = value;//修改和   
        return;  
    }  
    else  
    {  
        int mid = (xTree->left+xTree->right)/2;  
        if (point <= mid)    //往左子树搜索   
            Modify(xTree->lchild,point,value);   
        else                 //往右子树搜索   
            Modify(xTree->rchild,point,value);  
        xTree->max = maxValue(xTree->lchild->max,xTree->rchild->max);//修改最大值:从下往上    
        xTree->sum = xTree->lchild->sum + xTree->rchild->sum;        //修改和 :下->上   
    }  
    return;  
}   
//2.求连续一段格子权值和  
int GeziSum(XNode *xTree, int left, int right)  
{  
    if (left == xTree->left && right == xTree->right) //找到该线段   
        return xTree->sum;  
    else  
    {  
        int mid = (xTree->left+xTree->right)/2;  
        if (right <= mid)    //往左子树搜索   
            return GeziSum(xTree->lchild,left,right);   
        else if (left > mid) //往右子树搜索   
            return GeziSum(xTree->rchild,left,right);  
        else                 //分叉:左右搜索"和"值  
            return GeziSum(xTree->lchild,left,mid) + GeziSum(xTree->rchild,mid+1,right);  
    }  
}   
//3.求连续一段格子的最大值   
int GeziMax(XNode *xTree, int left, int right)  
{  
    if (left == xTree->left && right == xTree->right) //找到该线段   
        return xTree->max;  
    else  
    {  
        int mid = (xTree->left+xTree->right)/2;  
        if (right <= mid)    //往左子树搜索   
            return GeziMax(xTree->lchild,left,right);   
        else if (left > mid) //往右子树搜索   
            return GeziMax(xTree->rchild,left,right);  
        else  //分叉:返回搜索到的最大值   
            return maxValue(GeziMax(xTree->lchild,left,mid),GeziMax(xTree->rchild,mid+1,right));  
    }  
}   
//主函数   
int main()  
{  
    int m = 0, n = 0, i = 0, j = 0;  
    XNode *xTree = NULL;  
    int input[100000][3] = {0};  //input[][0]:操作序号,input[][1]:x,input[][2]:y   
    int Gezi = 0;   
    scanf("%d%d",&n,&m);         //n:格子个数, m:操作次数  
    xTree = CreateXTree(1,n);    //创建线段树,区间:1~n   
    for (i = 1; i <= n; ++i)     //给格子赋权值,Gezi;  
    {   
        scanf("%d",&Gezi);   
        Insert(xTree,i,Gezi);    //给线段树赋值   
    }  
    for (i = 0; i < m; ++i)  
        for (j = 0; j < 3; ++j)  //一个循环,输入3次:0,1,2   
            scanf("%d",&input[i][j]);  
    for (i = 0; i < m; ++i)      //执行操作   
    {  
        switch(input[i][0])  
        {  
case 1:Modify(xTree,input[i][1],input[i][2]); 
break;//修改线段权值   
            case2:printf("%d\n",GeziSum(xTree,input[i][1],input[i][2]; 		break;//返回线段和   
case3:printf("%d\n",GeziMax(xTree,input[i][1],input[i][2]; 			break;//返回线段最大值   
default:break;  
        }  
    }  
    return 0;  
}  


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值