• 线段树 + 树状数组 【小谈】



    线段树和树状数组就学了以下一点,并且还是几个月前学的,说明这段时间数据结构没一点长进......还是先记录一下吧, 至于离散化,眼下做的题目较少,先不写了。还要学区间操作、扫描线......任重而道远。

     


    问题一:给你N个数和M次操作,操作分两种——

    1,U a b 第a个数添加b;2,S a b  求区间[a, b]的和。


    这类问题树状数组能够非常简洁的实现:


    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #define MAXN 100000+10
    using namespace std;
    int sum[MAXN<<1];
    int N, M;
    int lowbit(int x)
    {
        return x & (-x);
    }
    void update(int x, int d)
    {
        while(x <= N)
        {
            sum[x] += d;
            x += lowbit(x);
        }
    }
    int query(int x)
    {
        int ans = 0;
        while(x > 0)
        {
            ans += sum[x];
            x -= lowbit(x);
        }
        return ans;
    }
    int main()
    {
        while(scanf("%d%d", &N, &M) != EOF)
        {
            memset(sum , 0, sizeof(sum));
            int a, b;
            char op[10];
            for(int i = 1; i <= N; i++)
            {
                scanf("%d", &a);
                update(i, a);
            }
            while(M--)
            {
                scanf("%s%d%d", op, &a, &b);
                if(op[0] == 'U')
                    update(a, b);
                else
                    printf("%d
    ", query(b) - query(a-1));
            }
        }
        return 0;
    }
    

    问题二:给你N个数和M次操作。操作分三种——

    1,U a b 第a个数变成b;2,S a b 求区间[a, b]的和;3。M a b 求区间[a, b]的最大值 


    线段树实现:

    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #define MAXN 100000+10
    using namespace std;
    int sum[MAXN<<2];
    int Max[MAXN<<2];
    void PushUp(int o)
    {
        sum[o] = sum[o<<1] + sum[o<<1|1];
        Max[o] = max(Max[o<<1], Max[o<<1|1]);
    }
    void build(int o, int l, int r)
    {
        if(l == r)
        {
            scanf("%d", &sum[o]);
            Max[o] = sum[o];
            return ;
        }
        int mid = (l + r) >> 1;
        build(o<<1, l, mid);
        build(o<<1|1, mid+1, r);
        PushUp(o);
    }
    void update(int o, int l, int r, int pos, int val)
    {
        if(l == r)
        {
            Max[o] = sum[o] = val;//若是添加 直接加上val值
            return ;
        }
        int mid = (l + r) >> 1;
        if(pos <= mid)
            update(o<<1, l, mid, pos, val);
        else
            update(o<<1|1, mid+1, r, pos, val);
        PushUp(o);
    }
    int querysum(int o, int l, int r, int L, int R)
    {
        if(L <= l && R >= r)
            return sum[o];
        int mid = (l + r) >> 1;
        int ans = 0;
        if(R <= mid)
            ans += querysum(o<<1, l, mid, L, R);
        else if(L > mid)
            ans += querysum(o<<1|1, mid+1, r, L, R);
        else
        {
            ans += querysum(o<<1, l, mid, L, mid);
            ans += querysum(o<<1|1, mid+1, r, mid+1, R);
        }
        return ans;
    }
    int querymax(int o, int l, int r, int L, int R)
    {
        if(L <= l && R >= r)
            return Max[o];
        int mid = (l + r) >> 1;
        int ans = 0;
        if(R <= mid)
            ans = max(querymax(o<<1, l, mid, L, R), ans);
        else if(L > mid)
            ans = max(querymax(o<<1|1, mid+1, r, L, R), ans);
        else
        {
            ans = max(querymax(o<<1, l, mid, L, mid), ans);
            ans = max(querymax(o<<1|1, mid+1, r, mid+1, R), ans);
        }
        return ans;
    }
    int main()
    {
        int N, M;
        while(scanf("%d%d", &N, &M) != EOF)
        {
            build(1, 1, N);
            int a, b;
            char op[10];
            while(M--)
            {
                scanf("%s%d%d", op, &a, &b);
                if(op[0] == 'U')
                    update(1, 1, N, a, b);
                else if(op[0] == 'S')
                    printf("%d
    ", querysum(1, 1, N, a, b));
                else
                    printf("%d
    ", querymax(1, 1, N, a, b));
            }
        }
        return 0;
    }
    
    

    问题三:给你N个数和M次操作,操作有两种——

    1。A a b c 区间[a, b]全部数改动为c; 2。 Q a b 求区间[a, b]全部数之和。


    #include <cstdio>
    #define MAX 100000+10
    int col[MAX<<2];
    int sum[MAX<<2];
    void PushUp(int o)
    {
        sum[o] = sum[o<<1] + sum[o<<1|1];
    }
    void PushDown(int o, int m)
    {
        if(col[o])
        {
            col[o<<1] = col[o<<1|1] = col[o];
            sum[o<<1] = (m - (m >> 1)) * col[o];
            sum[o<<1|1] = (m >> 1) * col[o];
            col[o] = 0;
        }
    }
    void build(int o, int l, int r)//建树
    {
        col[o] = 0;
        if(l == r)
        {
            scanf("%d",&sum[o]);
            return ;
        }
        int mid = (l + r) >> 1;
        build(o<<1,l, mid);
        build(o<<1|1, mid+1, r);
        PushUp(o);
    }
    void update(int o, int l, int r, int L, int R, int v)//更新
    {
        if(L <= l && r <= R)
        {
            col[o] = v;
            sum[o] = v * (r - l + 1);
            return ;
        }
        PushDown(o , r - l + 1);
        int mid = (l + r) >> 1;
        if (L <= mid) update(o<<1, l, mid, L , R , v);
        if (R > mid) update(o<<1|1, mid+1, r, L , R , v);
        PushUp(o);
    }
    int query(int o, int l, int r, int L, int R) //查询
    {
        if(L <= l && R >= r)
        {
            return sum[o];
        }
        PushDown(o, r-l+1);
        int mid = (r+l) >> 1;
        int res = 0;
        if(L <= mid)
        res += query(o<<1, l, mid, L, R);
        if(R > mid)
        res += query(o<<1|1, mid+1 , r, L, R);
        return res;
    }
    int main()
    {
        int N, M;
        int a, b, v;
        char op;
        while(scanf("%d%d", &N, &M)!=EOF)
        {
            build(1, 1, N);
            while(M--)
            {
                getchar();
                scanf("%c", &op);
                if(op == 'A')
                {
                    scanf("%d%d%d", &a, &b, &v);//把区间[a,b]全部数全部改为v
                    update(1, 1, N, a, b, v);
                }
                else if(op == 'Q')
                {
                    scanf("%d%d", &a, &b);//求区间[a,b]全部数之和
                    printf("%d
    ", query(1, 1, N, a, b));
                }
            }
        }
        return 0;
    }
    


    问题四:给你N个数和M次操作,操作分两种——

    1,C a b c 把区间[a, b]全部数全加c。 2。Q a b 求区间[a, b]全部数之和。


    #include<cstdio>
    #include<cstring>
    #define MAX 100000+10
    using namespace std;
    int sum[MAX<<2];
    int add[MAX<<2];
    void PushUp(int o)
    {
        sum[o] = sum[o<<1] + sum[o<<1|1];
    }
    void PushDown(int o, int m)
    {
        if(add[o])
        {
            add[o<<1]   += add[o];
            add[o<<1|1] += add[o];
            sum[o<<1]   += add[o] * (m-(m>>1));
            sum[o<<1|1] += add[o] * (m>>1);
            add[o] = 0;
        }
    }
    void build(int o,int l,int r)//建树
    {
        add[o] = 0;
        if(l == r)
        {
            scanf("%d",&sum[o]);
            return ;
        }
        int mid = (r+l) >> 1;
        build(o<<1, l, mid);
        build(o<<1|1, mid+1, r);
        PushUp(o);
    }
    void update(int o, int l, int r, int L, int R, int v)//更新
    {
        if(L <= l && R >= r)
        {
            add[o] += v;
            sum[o] += v * (r-l+1);
            return ;
        }
        PushDown(o, r-l+1);
        int mid = (r+l) >> 1;
        if(L <= mid) update(o<<1, l, mid, L, R, v);
        if(R >mid) update(o<<1|1, mid+1, r, L, R, v);
        PushUp(o);
    }
    int query(int o, int l, int r, int L, int R)//查询
    {
        if(L <= l && R >= r)
        {
            return sum[o];
        }
        PushDown(o, r-l+1);
        int mid = (r+l) >> 1;
        int res = 0;
        if(L <= mid)
        res += query(o<<1, l, mid, L, R);
        if(R >mid)
        res += query(o<<1|1, mid+1, r, L, R);
        return res;
    }
    int main()
    {
        int N, M;
        int a, b, v;
        char op;
        while(scanf("%d%d", &N, &M), N||M)
        {
            build(1, 1, N);
            while(M--)
            {
                getchar();
                scanf("%c", &op);
                if(op == 'C')//区间[a,b]每一个数自加 v
                {
                    scanf("%d%d%d", &a, &b, &v);
                    update(1, 1, N, a, b, v);
                }
                else if(op == 'Q')//区间[a,b]全部数之和
                {
                    scanf("%d%d", &a, &b);
                    printf("%d
    ", query(1, 1, N, a, b));
                }
            }
        }
        return 0;
    }
    


  • 相关阅读:
    R语言入门心得(1) -- 下载与安装
    ASP.NET中ListView用DataPager分页
    .Net平台下的扩展方法
    疑问句
    时态
    webapi put 404
    记一次阿里云ECS服务器图片资源迁移至 阿里云 oss
    javascript
    阿里云 oss 上传文件,js直传,.net 签名,回调
    redis 持久化共享 Session
  • 原文地址:https://www.cnblogs.com/tlnshuju/p/7227171.html
Copyright © 2020-2023  润新知