今天学习了线段树的三个基本操作 建树 更新 查找
先理解下什么是线段树
就这个题目而言 如果我们用普通的数组去存放 然后依次遍历访问的话 时间太多了
线段树利用了二分的思想 把数据以段的形式进行储存 这样在访问的时候 时间复杂度就下来了
上图就是线段树的一个简单的模型
创建线段树(初始化)】:
由于线段树是用二叉树结构储存的,而且是近乎完全二叉树的,所以在这里我使用了数组来代替链表上图中区间上面的红色数字表示了结构体数组中对应的下标。
在完全二叉树中假如一个结点的序号(数组下标)为 I ,那么 (二叉树基本关系)
I 的父亲为 I/2,
I 的另一个兄弟为 I/2*2 或 I/2*2+1
I 的两个孩子为 I*2 (左) I*2+1(右)
这段来自其他同学的博客 这个是建树的基础 我们用标号来链接每个叶节点
struct node { int maxx; int l,r; }stu[maxn*4]; 这个结构体就是每一个线段树的一个叶 其中有左右节点以及本题需要的max值
先说说建树操作把
int mid=(l+r)/2; stu[i].l=l; stu[i].r=r;
既然利用到了二分的思想 那么 这几步是少不了的
void buildtree(int i,int l,int r)//建树 { int mid=(l+r)/2; stu[i].l=l; stu[i].r=r; if(l==r) { stu[i].maxx=a[l]; return; } buildtree(i*2,l,mid);//构建左子点 buildtree(i*2+1,mid+1,r);//构建右子点 stu[i].maxx=max(stu[i*2].maxx,stu[i*2+1].maxx);//在递归结束回溯的时候 把最大值返回
}
再说说数据的更新
更新的话 先得二分找到目标位置 然后替换 最后还得依次更新最大值的数据
void updata(int i)//更新 { int l=stu[i].l; int r=stu[i].r; int mid=(l+r)/2;//二分咯 if(l==r&&r==x)//x为目标id 当左右节点相同的时候 就是找到这个数的时候 { stu[i].maxx=y; return; } if(l<=x&&x<=mid) updata(i*2);//向左找 else updata(i*2+1);//向右找 stu[i].maxx=max(stu[i*2].maxx,stu[i*2+1].maxx);//回溯的时候 更新max的数据 }
最后就是询问过程了
找最大值的过程中 要把要求的区间分段 即分割成好几个小段 然后放在建好的书里面找
int que(int a,int b,int i)//查找 { int l=stu[i].l; int r=stu[i].r; int mid=(l+r)/2; if(l==a&&r==b) return stu[i].maxx; if(b<=mid) return que(a,b,i*2);//全在右边 else if(a>mid) return que(a,b,i*2+1);//全在左边 else return max(que(a,mid,i*2),que(mid+1,b,i*2+1));//需要分割的话 取分开的最大 }
上完整代码
#include<cstdio> #include<iostream> #include<string.h> using namespace std; #define maxn 200010 struct node { int maxx; int l,r; }stu[maxn*4]; int a[maxn]; int n,m,x,y; void buildtree(int i,int l,int r)//建树 { int mid=(l+r)/2; stu[i].l=l; stu[i].r=r; if(l==r) { stu[i].maxx=a[l]; return; } buildtree(i*2,l,mid); buildtree(i*2+1,mid+1,r); stu[i].maxx=max(stu[i*2].maxx,stu[i*2+1].maxx); } void updata(int i)//更新 { int l=stu[i].l; int r=stu[i].r; int mid=(l+r)/2; if(l==r&&r==x) { stu[i].maxx=y; return; } if(l<=x&&x<=mid) updata(i*2); else updata(i*2+1); stu[i].maxx=max(stu[i*2].maxx,stu[i*2+1].maxx); } int que(int a,int b,int i)//查找 { int l=stu[i].l; int r=stu[i].r; int mid=(l+r)/2; if(l==a&&r==b) return stu[i].maxx; if(b<=mid) return que(a,b,i*2); else if(a>mid) return que(a,b,i*2+1); else return max(que(a,mid,i*2),que(mid+1,b,i*2+1)); } int main() { char z; cin.sync_with_stdio(false); while(cin>>n>>m) { for(int i=1;i<=n;i++) cin>>a[i]; buildtree(1,1,n); while(m--) { cin>>z>>x>>y; if(z=='U') { updata(1); } else { cout<<que(x,y,1)<<endl; } } } return 0; }