5 6
1 2 3 4 5
Q 1 5
U 3 6
Q 3 4
Q 4 5
U 2 9
Q 1 5
5 6 5 9
#include<iostream> #include<cstdio> #include<algorithm> #include<cmath> #include<string> #include<cstring> using namespace std; const int SIZE=30005; int a[SIZE]; struct SegmentTree{ int l,r; int dat; } t[SIZE*4];//struct数组存储线段树 void build(int p,int l,int r){ t[p].l=l;t[p].r=r;//节点p表示区间l-r if(l==r){ t[p].dat=a[l]; return; }//叶节点 int mid=(l+r)/2;//折半 build(p*2,l,mid);//左子节点[l,mid],编号p*2 build(p*2+1,mid+1,r); //右子节点[mid+1,r],编号p*2+1 t[p].dat=max(t[p*2].dat,t[p*2+1].dat);//从下往上传递信息 } int ask(int p,int l,int r)//查询区间最大值 { if(l<=t[p].l&&r>=t[p].r)//完全包含 return t[p].dat; int mid=(t[p].l+t[p].r)/2; int val=-(1<<30);//无穷小 if(l<=mid) val=max(val,ask(p*2,l,r));//左子节点有重叠 if(r>mid) val=max(val,ask(p*2+1,l,r)); //右子节点有重叠 return val; } void change(int p,int x,int v){//单点修改 if(t[p].l==t[p].r){//找到叶节点 t[p].dat=v; return; } int mid=(t[p].l+t[p].r)/2; if(x<=mid) change(p*2,x,v);//x属于左半区间 else change(p*2+1,x,v); //x属于右半区间 t[p].dat=max(t[p*2].dat,t[p*2+1].dat);//从下往上更新信息 } int main() { int n,m; while(cin>>n>>m){ memset(a,0,sizeof(a)); for(int i=1;i<=n;i++) cin>>a[i]; build(1,1,n); for(int i=1;i<=m;i++){ char c; cin>>c; int a,b; cin>>a>>b; if(c==‘Q‘){ cout<<ask(1,a,b)<<endl; } if(c==‘U‘) change(1,a,b); } } return 0; }
通过线段树可以快速进行单点更新 和 查询区间最大值
相当于一个非常巧妙的递归
先从上往下到叶节点
再将叶节点往上不断进行比较取出最大值
再从下回到起点
至于线段树的讲解
可以先看一下下面的讲解哦
https://www.cnblogs.com/Tidoblogs/p/10887555.html
原文:https://www.cnblogs.com/Tidoblogs/p/10887624.html