zoukankan      html  css  js  c++  java
  • 线段树及其基本操作

    处理何种问题:数组单点更新,单点查询,区间更新,区间求和,区间求最值。

     

    性能:时间复杂度为O(logn)

     

    原理:区间跟新的懒惰标记了解一下,其余略

     

    实现步骤:略

     

    备注:在线段树里,单点更新与单点累加和树状数组上的单点跟新有区别,树状数组还需与原数组求差值,线段树不用。

    线段树的区间求最值差别不大,在此贴一份A过题的最值代码,用来对比找bug。

    #include<iostream>
    
    #include<cstdio>
    
    #include<string.h>
    
    #include<algorithm>
    
    using namespace std;
    
     
    
    const int MaxN=200010;
    
     
    
    struct node
    
    {
    
        int l,r,w;
    
    };
    
    node tree[MaxN*4];
    
    int num[MaxN];
    
    int n,ctor,x,ans,a,b,y;
    
     
    
    void built(int k,int ll,int rr)
    
    {
    
        tree[k].l=ll;
    
        tree[k].r=rr;
    
        if(tree[k].l==tree[k].r)
    
        {
    
            tree[k].w=num[ctor++];
    
        }
    
        else
    
        {
    
            int m=(ll+rr)/2;
    
            built(k*2,ll,m);
    
            built(k*2+1,m+1,rr);
    
            tree[k].w=max(tree[k*2].w,tree[k*2+1].w);
    
        }
    
    }
    
     
    
    void change_point(int k)
    
    {
    
        if(tree[k].l==tree[k].r)
    
        {
    
            tree[k].w=y;
    
        }
    
        else
    
        {
    
            int m=(tree[k].l+tree[k].r)/2;
    
            if(x<=m)
    
                change_point(k*2);
    
            else
    
                change_point(k*2+1);
    
            tree[k].w=max(tree[k*2].w,tree[k*2+1].w);
    
        }
    
    }
    
    void ask_interval(int k)
    
    {
    
        if(a<=tree[k].l&&tree[k].r<=b)
    
        {
    
            ans=max(ans,tree[k].w);
    
        }
    
        else
    
        {
    
            int m=(tree[k].l+tree[k].r)/2;
    
            if(a<=m)
    
                ask_interval(k*2);
    
            if(b>m)
    
                ask_interval(k*2+1);
    
        }
    
    }
    
     
    
    int main()
    
    {
    
        int m;
    
        while(~scanf("%d%d",&n,&m))
    
        {
    
            for(int i=1;i<=n;++i)   scanf("%d",&num[i]);
    
            ctor=1;
    
            built(1,1,n);
    
            while(m--)
    
            {
    
                char c;
    
                getchar();
    
                scanf("%c",&c);
    
                if(c=='Q')//查询
    
                {
    
                    scanf("%d%d",&a,&b);
    
                    ans=-100;
    
                    ask_interval(1);
    
                    printf("%d
    ",ans);
    
                }
    
                else if(c=='U')//单点更新
    
                {
    
                    scanf("%d%d",&x,&y);
    
                    change_point(1);
    
                }
    
            }
    
        }
    
        return 0;
    
    }
    

      

     

    输入样例解释

    9//n个元素

    1 2 3 4 5 6 7 8 9

    1 5//单点查询为1,x为坐标,从1开始计数

    2 5 0//单点修改为2,x为坐标,y为更新值,

    3 1 5//区间查询为3,查询[a,b]区间内的元素和,

    4 1 5 10//区间更新为4,将[a,b]区间内的元素均加y

    输出样例解释

    5 //对于1的操作

    10//对于3的操作输出

    #include<iostream>
    #include<cstdio>
    #include<string.h>
    #include<algorithm>
    using namespace std;
    const int MaxN=100010;
    struct node
    {
        int l,r,w,f;//左边界,右边界,值,懒惰标记
    };
    node tree[MaxN*4];
    int num[MaxN];//原序列
    int n,ctor,x,ans,a,b,y;//元素个数,建树是计数变量,单点查询时位置,左区间,右区间,区间修改值
    
    void built(int k,int ll,int rr)//建树
    {
        tree[k].l=ll;
        tree[k].r=rr;
        if(tree[k].l==tree[k].r)
        {
            tree[k].w=num[ctor++];
        }
        else
        {
            int m=(ll+rr)/2;
            built(k*2,ll,m);
            built(k*2+1,m+1,rr);
            tree[k].w=tree[k*2].w+tree[k*2+1].w;
        }
    }
    void down(int k)//懒惰标记
    {
        tree[k*2].f+=tree[k].f;
        tree[k*2+1].f+=tree[k].f;
        tree[k*2].w+=tree[k].f*(tree[k*2].r-tree[k*2].l+1);
        tree[k*2+1].w+=tree[k].f*(tree[k*2+1].r-tree[k*2+1].l+1);
        tree[k].f=0;
    }
    
    
    void ask_point(int k)//单点查询
    {
        if(tree[k].l==tree[k].r)
        {
            ans=tree[k].w;
        }
        else
        {
            if(tree[k].f)   down(k);
    
            int m=(tree[k].l+tree[k].r)/2;
            if(x<=m)
                ask_point(k*2);
            else
                ask_point(k*2+1);
        }
    }
    
    void change_point(int k)//单点更新
    {
        if(tree[k].l==tree[k].r)
        {
            tree[k].w+=y;
        }
        else
        {
            if(tree[k].f)   down(k);
            int m=(tree[k].l+tree[k].r)/2;
            if(x<=m)
                change_point(k*2);
            else
                change_point(k*2+1);
            tree[k].w=tree[k*2].w+tree[k*2+1].w;
        }
    }
    
    void ask_interval(int k)//区间查询
    {
        if(a<=tree[k].l&&tree[k].r<=b)
        {
            ans+=tree[k].w;
        }
        else
        {
            if(tree[k].f)   down(k);
            int m=(tree[k].l+tree[k].r)/2;
            if(a<=m)
                ask_interval(k*2);
            if(b>m)
                ask_interval(k*2+1);
        }
    }
    
    void change_interval(int k)//区间更新
    {
        if(a<=tree[k].l&&tree[k].r<=b)
        {
            tree[k].w+=(tree[k].r-tree[k].l+1)*y;
            tree[k].f+=y;
        }
        else
        {
            if(tree[k].f) down(k);
            int m=(tree[k].l+tree[k].r)/2;
            if(a<=m)
                change_interval(k*2);
            if(b>m)
                change_interval(k*2+1);
            tree[k].w=tree[k*2].w+tree[k*2+1].w;
        }
    }
    
    
    int main()
    {
        while(~scanf("%d",&n))//n 为元素个数
        {
            for(int i=1; i<=n; ++i)   scanf("%d",&num[i]);
            ctor=1;
            built(1,1,n);
    
            int m;//操作次数
            scanf("%d",&m);
            while(m--)
            {
                int Q;
                scanf("%d",&Q);
                ans=0;
                if(Q==1)//单点查询
                {
                    scanf("%d",&x);
                    ask_point(1);
                    printf("%d
    ",ans);
                }
                else if(Q==2)//单点更新
                {
                    scanf("%d%d",&x,&y);
                    change_point(1);
                }
                else if(Q==3)//区间查询
                {
                    scanf("%d%d",&a,&b);
                    ask_interval(1);
                    printf("%d
    ",ans);
                }
                else if(Q==4)//区间更新
                {
                    scanf("%d%d%d",&a,&b,&y);
                    change_interval(1);
                }
            }
        }
        return 0;
    }
    

      

  • 相关阅读:
    orcal下的中国大陆地热、重力网络数据库(用户网页模块设计)
    学生管理系统毕业论文
    图像效果算法设计—静态效果
    数字温度计(单片机课程设计)
    Orcal下的中国大陆地热、重力网络数据库(数据库模块设计)
    电脑公司财务管理系统(论文+论计)
    明天开始开年会!
    今天北京下雪了!
    三天年会开完了!
    页面元素添加提示(tooltip)
  • 原文地址:https://www.cnblogs.com/l1l1/p/9634202.html
Copyright © 2011-2022 走看看