时间限制: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。
画图什么的不太会,,不过题目提示用线段树,,,据我查阅资料,,得知就是满二叉树,,,
对题目的要求,,,可以将无用的点设为0即可
#include <stdio.h>
#include <string.h>
#define MAX 1<<18
int dat[MAX][4];
int n,m;
int max(int a, int b)
{
return a>b?a:b;
}
int tty()//n个节点建立的最低满二叉树的最后一层的节点数
{
int i=1;
while(i<n)
i *= 2;
return i;
}
void init()
{
int i = tty()-1;//第一个需要更新的节点编号
int k,j;
while(i >= 1)
{
j = i*2;//左海子
k = i*2+1;//右孩子
dat[i][0] = max(dat[j][0],dat[k][0]);//最大值
dat[i][1] = dat[j][1]+dat[k][1];//总和
dat[i][2] = dat[j][2];//左区间
dat[i][3] = dat[k][3];//右区间
i--;
}
}
void update(int a, int b)
{
int i=tty()+a-1;//更新的位置
int j;
dat[i][1] = dat[i][0] = b;
while(i > 1)
{
j = i/2;//更新的父亲节点
dat[j][0] = max(dat[j*2][0],dat[j*2+1][0]);
dat[j][1] = dat[j*2][1]+dat[j*2+1][1];
i = j;
}
}
int llsum(int a,int b, int c)
{
if(b==dat[a][2] && c==dat[a][3])
return dat[a][1];
int middle = (dat[a][2]+dat[a][3])/2;
if(c <= middle)
return llsum(a*2,b,c);
else if(b > middle)
return llsum(a*2+1,b,c);
else
return llsum(a*2,b,middle)+llsum(a*2+1,middle+1,c);
}
int query(int a,int b, int c)
{
if(b==dat[a][2] && c==dat[a][3])
return dat[a][0];
int middle = (dat[a][2]+dat[a][3])/2;
if(c <= middle)
return query(a*2,b,c);
else if(b > middle)
return query(a*2+1,b,c);
else
return max(query(a*2,b,middle),query(a*2+1,middle+1,c));
}
int main()
{
int i,j,k,a,b,c,q;
memset(dat,0,sizeof(dat));
scanf("%d%d",&n,&m);
i = tty();//起始元素的位置
j = i*2-1;//最后一个元素的位置
k = 1;//元素的区间编号
q = i+n-1;//结束元素的位置
for( ; i<=q; i++)
{
scanf("%d",&dat[i][0]);
dat[i][1] = dat[i][0];
}
j = i = tty();//起始元素的位置
//j = j/2+1;//最后一层进行区间编号的个数
while(k <= j)
{
dat[i][2] = dat[i][3] = k;
k++;
i++;
}
j = (tty()-1)*2;//最后一个元素的位置
init();//初始化,建立线段树
for(i=1; i<=m; i++)
{
scanf("%d%d%d",&a,&b,&c);
if(a == 1)//更新
update(b,c);
else if (a == 2)//区间和
printf("%d\n",llsum(1,b,c));
else//b、c区间的最大值
printf("%d\n",query(1,b,c));
}
return 0;
}
感觉不是很成熟,,,希望大家多多指点,帮助改进