毕竟是写给自己看的
还是写好看一点吧
一、
最简单的
题意~
给出N个数,两种操作:
1、U x y:修改第x个数的值为y;
2、Q x y:求第x到第y个的最大值,注:x未必比y小
标准的线段树对不对
我们可以理解成总裁管左右两个总经理,总经理管左右两个副总经理,副总经理管左右两个经理……每个管理者都只知道自己的值,不知道他们手下的值,所以他们每次都要问自己的手下,而他们的手下每次更新的时候都要反馈给上司……这样就很好理解了
#include<cstring>
#include<cstdio>
using namespace std;
int a[210000];//员工,只负责一开始表达自己的值
struct node //管理者(假设它是经理),管理者绝对不是员工,一定要分开来
//最底层的管理者只管一个员工,绝对不能想着:反正一个员工,就自己管自己算了。
//理解:有N个员工,就配有2N-1个管理者,用空间换时间
{
int l,r,lc,rc,c;// 管理的员工编号是第l个到第r个(连续),lc表示左副经理的编号,rc表示右副经理是谁
//c表示第l个员工至第r个员工的特征值:可以是和、最大值、或者最小值
}tr[410000]; int len;//tr数组就是管理者数组,len表示当前申请到第几个管理者
//到此,员工有自己的编号,管理者也有自己的编号
int mymax(int x,int y){ return x>y?x:y;} //求x和y最大值的函数
void bt(int l,int r) // build tree建立线段树,申请一个管理者,管理第l个员工至第r个员工
{
len++; int now=len;// now记录当前管理者的编号
tr[now].l=l; tr[now].r=r; tr[now].lc=tr[now].rc=-1;tr[now].c=0;//一开始当前管理者now的左右副总经理都是没人-1,管理者管理范围最大值为0,这里五个元素都要赋值
if(l<r) //如果管的人大于1人,就有权申请两个副总经理帮忙管人
{
int mid=(l+r)/2; // mid为l和r的中间值,从中间分为两段[l,mid]和[mid+1,r]
tr[now].lc=len+1; bt( l , mid ); // [l,mid]给左副总管,让他先去管好[l,mid]
tr[now].rc=len+1; bt( mid+1 , r ); // [mid+1,r]给右副总管,让他先去管好[mid+1,r]
}
}
void change(int now,int x,int k)//change的功能:在当前管理者now的管理范围内,把管第x个员工的管理者(不知道该管理者的编号)的值改为k
//理解:为什么第x个一定在now的管理范围内呢?
//注意:修改,改的是管理者,不是改员工,员工已经没用了。
{
if( tr[now].l==tr[now].r) { tr[now].c=k;return ;}//如果now只管一人,那么这个人的编号一定是x,为什么?
int lc= tr[now].lc, rc=tr[now].rc;//找出now的左右副总分别是谁
int mid=( tr[now].l+ tr[now].r)/2;//找到now管理范围的中间位置
if( x<=mid) change(lc,x,k); //如果x在now的左副总的管理范围,那么修改这件事就交给左副总去做
else if( mid+1<=x) change(rc,x,k); //如果x在now的右副总的管理范围,那么修改这件事就交给右副总去做
tr[now].c= mymax( tr[ lc ] .c , tr[ rc ].c );//修改完后,注意要维护,有可能最大值发生变化了
}
int findmax(int now,int l,int r)//findmax的功能:在当前管理者now的管理范围内,找出第l个员工至第r个员工的最大值
{
if( l== tr[now].l && tr[now].r== r) return tr[now].c;//如果now的管理范围刚好是[l,r],就不用问左右副总了
int lc= tr[now].lc, rc=tr[now].rc;
int mid=( tr[now].l+ tr[now].r)/2;
if( r<=mid) return findmax(lc,l,r); //[l,r]在左副总的管理范围内
else if( mid+1<=l) return findmax(rc,l,r); //[l,r]在右副总的管理范围内
else return mymax( findmax(lc,l,mid) , findmax(rc,mid+1,r) );//其他情况就是[l,r]一部分在左副总,一部分在右副总
}
int main()
{
int n,m,i,x,y; char ss[10];
while( scanf("%d%d",&n,&m)!=EOF)
{
for(i=1;i<=n;i++) scanf("%d",&a[i]);
len=