好久没做算法题了,今天做了一道,又是百度又是思考的,忙活了大半天(半天多),终于把它 AC 了。我去,看来真是忘得差不多了。
这是一道最基础的线段树。当然,这道题也可以用树状数组来做。
就当是复习一下线段树了。
线段树是这样一棵树,它是一棵二叉树,每个树的节点是一个区间,他的两个孩子节点的区间正好平分他。还可能保存有其他数据,比如说这个区间内的和。树一般用指针来表示,但是线段树大多用结构体数组来实现二叉树(听说是因为用数组比指针快)。一个下标为 i(从 1 开始) 的节点,它的左孩子节点下标为 2 * i;右孩子节点下标为 2 * i + 1。这样,就可以完美的构造一颗线段树了。
本题很简单,题意就是给一个数字序列 A1-An,然后很多询问,每个询问只有两种,一个更新某一个(Ai)数据,一个查询从 Am - An 中谁的值最大。怎么样,很简单吧。
#include<stdio.h>
#include<stdlib.h>
#include<math.h>
#define MAX 1000010
typedef struct node{
int l;
int r;
int value;
}Node;
int father[ MAX ];
int A[ MAX ];
Node nodes[ MAX ];
void build(int l,int r,int i){
nodes[ i ].l = l;
nodes[ i ].r = r;
nodes[ i ].value = 0;
if(l == r){
father[ l ] = i;
nodes[ i ].value = A[ l ];
while(i != 0){
if(nodes[ i / 2 ].value < nodes[ i ].value)
nodes[ i / 2 ].value = nodes[ i ].value;
i /= 2;
}
return;
}
build(l, (int)floor((l + r)/2.0), i * 2);
build((int)floor((l + r)/2.0) + 1, r, i * 2 + 1);
}
void Query(int l,int r,int i,int * x){
if(nodes[i].l==l && nodes[i].r==r){
(*x)=((*x) < nodes[i].value) ? nodes[i].value : (*x);
return ;
}
i = i<<1;
if(l <= nodes[i].r){
if(r<=nodes[i].r)
Query(l,r,i,x);
else
Query(l,nodes[i].r,i,x);
}
i+=1;
if(r>=nodes[i].l)
if(l>=nodes[i].l)
Query(l,r,i,x);
else
Query(nodes[i].l,r,i,x);
}
void Update(int x){
int y,a,b;
if(x == 1) return;
y = x / 2;
a=nodes[y<<1].value;
b=nodes[(y<<1)+1].value;
nodes[y].value = (a>b)?a:b;
Update(x/2);
}
int main()
{
int i,SN,QN,m,n;
int *x=(int *)malloc(sizeof(int));
char s[10];
while(scanf("%d%d",&SN,&QN)!=EOF){
for(i=1; i<=SN; i ++){
scanf("%d",&A[i]);
}
build(1,SN,1);
for(i=0;i<QN;i++){
(*x) = 0;
scanf("%s%d%d",s,&m,&n);
if(s[0]=='Q'){
Query(m,n,1,x);
printf("%d\n",(*x));
}
if(s[0]=='U'){
nodes[father[m]].value = n;
Update(father[m]);
}
}
}
}
参考了很多线段树代码,勉强给写出来了。