Fork me on GitHub

【常用模板】 线段树单点操作

输入
第一行两个整数n,m,第二行n个整数表示初始时的数组A[ ];
接下来m行,每行3个整数a,b,c,如果a=1,那么输出A[b]~A[c]中最大的数
若a=2,那么将A[b]改为c
输出
每行输出一个整数,对应每一个操作a=1

超级简单的线段树模板题,一遍就过了,子程序太多,变量更多,容易搞混很尴尬,就在几周前的noip中,有一个dalao给我们得瑟说他会线段树,千方百计地得瑟(虽然他考得并不好23333),然后羡慕的我们口水横流啊,今天才发现,线段树其实挺简单的,废话不多说,直接贴代码

#include <iostream>
using namespace std;
int st[11000],a[11000],sr[11000];
void build(int z,int l,int r)
{
    if(l==r)
        st[z]=a[l];
    else
    {
        int mid=(l+r)/2;
        build(z*2,l,mid);
        build(z*2+1,mid+1,r);              //注意mid+1,不要忘了加一
        st[z]=max(st[z*2],st[z*2+1]);              //本题,求最大值
    }
}
void change(int z,int l,int r,int aim,int ans)
{
    if(l==r&&l==aim)
    {
        st[z]=ans;
        return;
    }
    int mid=(l+r)/2;
    if(aim<=mid)                      //这里aim<=mid不解释
        change(z*2,l,mid,aim,ans);
    else
        change(z*2+1,mid+1,r,aim,ans);         //加1加1加1别忘了
    st[z]=max(st[z*2],st[z*2+1]);             //最大值
}
int find(int z,int wl,int wr,int l,int r)   //wl想要的区间左节点,wr想要的区间右节点
{
    if(wl>r||wr<l)              //区间交叉,想要的区间不包含在正在搜寻的区间内
        return -1;              //返回一个无影响的值
    if(wl<=l&&wr>=r)
        return st[z];
    int mid=(l+r)/2;
    int le=find(z*2,wl,wr,l,mid),ri=find(z*2+1,wl,wr,mid+1,r);  //二分查询最大值
    return max(le,ri);
}
int main()
{
    int n,m;
    cin>>n>>m;
    for(int i=1;i<=n;i++)
        cin>>a[i];
    build(1,1,n);
    for(int i=1;i<=m;i++)
    {
        int x,y,z;
        cin>>x>>y>>z;
        if(x==2)
            change(1,1,n,y,z);
        if(x==1)
            cout<<find(1,y,z,1,n);
    }
    return 0;
} 

欢迎来顶

posted @ 2016-12-23 16:29  sxb门徒  阅读(170)  评论(0编辑  收藏  举报