AC的第一个线段树的题目,但不是做的第一个线段树题目。原来做过一两道吧,杭电上有一道,不过线段树超时了。。要用树状数组做,所以一直还没AC
这道题目写代码的时候,让我对于二分,和递归这两个重要思想都有了比较清晰的认识。
二分呢,一定要确定好两个部分的边界。决不能重复边界。
递归呢,注意递归分为迭代(从上到下)和回溯(从下到上)两个过程的。我们经常忽略第二个过程。
#include <cstdio>
#define max(x,y) ((x)>(y)?(x):(y))
int max;
struct Node
{
int L,R;
int max;
Node *pLeft,*pRight;
Node(){
pLeft=pRight=NULL;
max=0;
}
};/*很多人喜欢开个很大的节点数组来存放节点数据。左右儿子不是用指针而是用整型来存放数组下标。我不是很喜欢。我还是喜欢用指针。
不过有个坏处就是这样吃内存,每次都要记得销毁这个树*/
void initTree(Node *root,int L,int R)
{
root->L=L;
root->R=R;
if(L!=R)
{
Node *LNode = new Node();
Node *RNode = new Node();
root->pLeft=LNode;
root->pRight=RNode;
initTree(LNode,L,(L+R)/2);
initTree(RNode,(L+R)/2+1,R);
}
}
void insert(Node *root,int i,int s)
{
if(root->L==i&&root->R==i)
{
root->max=s;
return ;
}
if(i<=(root->L+root->R)/2)
insert(root->pLeft,i,s);
else if(i>=(root->L+root->R)/2+1)
insert(root->pRight,i,s);
root->max=max(root->pLeft->max,root->pRight->max);
}
void query(Node *root,int L,int R)
{
if(root->max<max)
return ;
if(root->L==L&&root->R==R)
{
max=root->max;
return ;
}
if((root->L+root->R)/2+1<=L)
query(root->pRight,L,R);
else if((root->L+root->R)/2>=R)
query(root->pLeft,L,R);
else
{
query(root->pLeft,L,(root->L+root->R)/2);
query(root->pRight,(root->L+root->R)/2+1,R);
}
}
void deleTree(Node *root)
{
if(root->pLeft)
deleTree(root->pLeft);
if(root->pRight)
deleTree(root->pRight);
delete(root);
}
int main()
{
int n,m;
while(scanf("%d%d",&n,&m)!=EOF)
{
Node *root = new Node();
initTree(root,1,n);
int tem;
for(int i=1;i<=n;i++)
{
scanf("%d",&tem);
insert(root,i,tem);
}
getchar();
char cmd;
int s,e;
for(int i=1;i<=m;i++){
scanf("%c%d%d",&cmd,&s,&e);
if(cmd=='Q')
{
max=0;
query(root,s,e);
printf("%d\n",max);
}
else if(cmd=='U')
{
insert(root,s,e);
}
getchar();
}
deleTree(root);
}
return 0;
}