zoukankan      html  css  js  c++  java
  • 浅谈具有各种特点的线段树

    有关线段树的各种版本我也是从去年结束OI之后就再也没有碰过了,现在看到各种树觉得也是无从下手晕的很,拖拖拉拉一直三四天才弄出来一个专题。

    重新扒出来看一眼各种树怎么写,然后写写博客记录一下心里历程(无言吐槽)

    言归正传,先来说一下我对线段树这个美好东西的理解。

    1.其实我觉得最简单的就是线段树的板子

    2.如果你看一道题看一份题解看不懂然后人家告诉你这是线段树你说“怎么可能这是线段树?” 这种现象非常正常。

    线段树专题一:单点更新

    题目形如:求某个区间内的最大值,更新某个节点之后求和等。总之就是不涉猎区间更新的问题(其实也就是TLE的问题,不然不TLE谁去用lazytag)

    I hate it(hdu 1754) 
    题目描述: 
    很多学校流行一种比较的习惯。老师们很喜欢询问,从某某到某某当中,分数最高的是多少。 
    这让很多学生很反感。不管你喜不喜欢,现在需要你做的是,就是按照老师的要求,写一个程序,模拟老师的询问。当然,老师有时候需要更新某位同学的成绩。 
    本题目包含多组测试 
    在每个测试的第一行,有两个正整数 N 和 M ( 0~N<=200000,0~M<5000 ),分别代表学生的数目和操作的数目。
    学生ID编号分别从1编到N。第二行包含N个整数,代表这N个学生的初始成绩,其中第i个数代表ID为i的学生的成绩。接下来有M行。每一行有一个字符 C (只取’Q’或’U’) ,和两个正整数A,B。 当C为’Q’的时候,表示这是一条询问操作,它询问ID从A到B(包括A,B)的学生当中,成绩最高的是多少。 当C为’U’的时候,表示这是一条更新操作,要求把ID为A的学生的成绩更改为B。 对于每一次询问操作,在一行里面输出最高成绩。 输入 本题目包含多组测试,请处理到文件结束。 在每个测试的第一行,有两个正整数 N 和 M 分别代表学生的数目和操作的数目。 学生ID编号分别从1编到N。 第二行包含N个整数,代表这N个学生的初始成绩,其中第i个数代表ID为i的学生的成绩。 接下来有M行。每一行有一个字符 C (只取’Q’或’U’) ,和两个正整数A,B。 当C为’Q’的时候,表示这是一条询问操作,它询问ID从A到B(包括A,B)的学生当中,成绩最高的是多少。 当C为’U’的时候,表示这是一条更新操作,要求把ID为A的学生的成绩更改为B。 输出 对于每一次询问操作,在一行里面输出最高成绩。 样例输入
    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<cstdio>
    #include<iostream>
    using namespace std;
    const int MAXX = 200000;
    struct node{
        int l,r,val;
    }tree[MAXX*4+5];
    
    int a[MAXX+5];
    int max(int x,int y){
        if(x>y){
            return x;
        }else{
            return y;
        }
    }
    int build(int p,int l,int r){
        tree[p].l=l;
        tree[p].r=r;
        if(l == r){
            tree[p].val = a[l];
        }
        int mid = (l+r)/2;
        int x1 = build(p<<1,l,mid);
        int x2 = build(p<<1|1,mid+1,r);
        tree[p].val = max(x1,x2);
        return tree[p].val;
    }
    int update(int p,int x){
        if(x<tree[p].l || x>tree[p].r)
            return tree[p].val;
        if(tree[p].l==tree[p].r)
        {   
            tree[p].val=a[tree[p].l];
            return tree[p].val;
        }
        int x1=update(2*p,x);
        int x2=update(2*p+1,x);
        tree[p].val=max(x1,x2);
        return tree[p].val;
    
    }
    int query(int p,int x,int y)//查询
    {
        if(y<tree[p].l || x>tree[p].r)
            return 0;
        if(x<=tree[p].l && tree[p].r<=y)
            return tree[p].val;
        int x1=query(2*p,x,y);
        int x2=query(2*p+1,x,y);
        return max(x1,x2);
    }
    
    int main(){
           int i,j,k,m,n;int x,y;char c;
        scanf("%d%d",&n,&m);
        for(i=1;i<=n;i++)   scanf("%d",&a[i]);
        create_tree(1,1,n);
        for(i=1;i<=m;i++)
        {
            getchar();
            scanf("%c%d%d",&c,&x,&y);
            if(c=='Q')
                {printf("%d
    ",query(1,x,y));}
            else
                {a[x]=y;update(1,x);}
        }
        return 0;
    
    }

     

    线段树专题二:区间更新

    这里就用lazytag了,不用会TLE..比如luogu的T3372

    #include<cstdio>
    #include<iostream>
    using namespace std;
    
    const int MAXX = 100000;
    
    struct node{
        int l,r;
        long long val,laz;
    }tree[MAXX*4+2];
    
    int a[MAXX+5];
    
    void build(int p,int l,int r){
        tree[p].l = l;
        tree[p].r = r;
        if(l == r){
            tree[p].val = a[l];
            return;
        }
        int mid = (l+r)/2;
        build(p<<1,l,mid);
        build(p<<1|1,mid+1,r);
        tree[p].val = tree[p<<1].val + tree[p<<1|1].val;
    }
    
    void pushdown(int p){
        if(tree[p].laz != 0){
            tree[p<<1].val += tree[p].laz*(tree[p<<1].r-tree[p<<1].l+1);
            tree[p<<1|1].val += tree[p].laz*(tree[p<<1|1].r-tree[p<<1|1].l+1);
            tree[p<<1].laz += tree[p].laz;
            tree[p<<1|1].laz += tree[p].laz;
            tree[p].laz = 0;
        }
    }
    
    void update(int p,int x,int y,int s){
        if(x<=tree[p].l && y>=tree[p].r){//包含
            tree[p].val+=(long long)s*(tree[p].r-tree[p].l+1);
            tree[p].laz+=s;
            return;
        }
        pushdown(p);
        int mid=(tree[p].l+tree[p].r)/2;
        if(y<=mid){
            update(p<<1,x,y,s);
        }else if(x > mid){
            update(p<<1|1,x,y,s);
        }else{
            update(p<<1,x,mid,s);
            update(p<<1|1,mid+1,y,s);
        }
        tree[p].val = tree[p<<1].val + tree[p<<1|1].val;
    }
    
    long long query(int p,int x,int y){
        if(x<=tree[p].l && y>=tree[p].r){
            return tree[p].val;
        }
        pushdown(p);
        long long ans=0;
        int mid=(tree[p].l+tree[p].r)/2;
        
        if(y<=mid){
            ans += query(p<<1,x,y);
        }else if(x > mid){
            ans += query(p<<1|1,x,y);
        }else{
            ans += query(p<<1,x,mid);
            ans += query(p<<1|1,mid+1,y);
        }
    
        return ans;
        
    }
    
    int main(){
        int n,m;
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;i++)
        scanf("%d",&a[i]);
        build(1,1,n);
        for(int i=1;i<=m;i++)
        {
            int q,x,y,z;
            scanf("%d",&q);
            if(q==1){
                scanf("%d%d%d",&x,&y,&z);
                update(1,x,y,z);
            }
            else {
                scanf("%d%d",&x,&y);
                cout<<query(1,x,y)<<endl;
            }
        }
        return 0;
    }

    先更新到这,时间不早,下次有时间继续更新

  • 相关阅读:
    Selenium2+python自动化55-unittest之装饰器(@classmethod)【转载】
    Selenium2+python自动化54-unittest生成测试报告(HTMLTestRunner)【转载】
    验证码在登录页面的使用
    习课省市区的三级联动(cxselect的使用)
    jira的使用
    springmvc 用拦截器+token防止重复提交
    springMVC发送邮件
    Commons-Collections 集合工具类的使用
    习课的视频播放器 video.js
    习课的redis配置记录
  • 原文地址:https://www.cnblogs.com/Fylsea/p/10554405.html
Copyright © 2011-2022 走看看