zoukankan      html  css  js  c++  java
  • 线段树+树状数组

    树状数组题目集:

    AHDU1556
    BPOJ2155
    CPOJ2299
    DPOJ3067
    EPOJ2352
    FPOJ2481
    GPOJ3321
    HPOJ1990

     

    数组一定要从1开始,因为根节点是从1开始的

    P3368 【模板】树状数组 2

    传送门:https://www.luogu.org/problemnew/solution/P3368

    这题名字叫树状数组,所以当然是向树状数组方向去写,可是我用朴素操作之后就tle了,

    之后看了大佬的博客才知道得树状数组差分一起用的

    https://blog.csdn.net/qq_41292370/article/details/82708214

    利用差分的性质优化区间修改操作的时间复杂度

    利用树状数组的性质优化查询操作的时间复杂度

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<queue>
    #include<stack>
    #include<vector>
    #include<map>
    #include<set>
    #include<bitset>
    #include<string>
    #include<cmath>
    #include<sstream>
    using namespace std;
    typedef long long ll;
    const double pi=acos(-1.0);
    const int eps=1e-10;
    const int mod=1e9+7;
    const int INF=0x3f3f3f3f;//int2147483647//ll9e18//unsigned ll 1e19
    const int maxn=500005;
    class TA
    {
        private:
            int e[maxn];
            int len;
            int lowbit(int k)
            {
                return k & (-k);
            }
        public:
            void add(int x,int v)                                                    //区间更新
            {
                while(x <= len)
                {
                    e[x] += v;
                    x += lowbit(x);
                }
            }
            void init(int* getin,int _len)                                            //初始化
            {
                len = _len;
                for(int i = 1;i <= len;i ++)
                {
                    add(i,*(getin + i - 1));
                 }
            }
            ll getsum(int x)                                                        //询问
            {
                ll sum = 0;
                while(x > 0)
                {
                    sum += e[x];
                    x -= lowbit(x);
                }
                return sum;
            }
    
    };
    
    TA ta;
    int a[maxn],n,t,m,b[maxn];
    int main()
    {
        scanf("%d%d",&n,&m);
        for(int i = 1;i <= n;i++)
        {
            scanf("%d",&a[i]);
        }
        b[1] = a[1];
        for(int i = 2;i <= n;i++)
        {
            b[i] = a[i] - a[i - 1];
        }
        ta.init(b + 1,n);
        while(m--)
        {
            int idenx,x,y,k;
            scanf("%d",&idenx);
            if(idenx == 1)
            {
                scanf("%d%d%d",&x,&y,&k);
                ta.add(x,k);
                ta.add(y + 1,-k);
            }
            else
            {
                scanf("%d",&x);
                printf("%lld
    ",ta.getsum(x));
            }
        }
        return 0;
    }
    View Code

     还有一种线段树解法。。。

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<queue>
    #include<stack>
    #include<vector>
    #include<map>
    #include<set>
    #include<bitset>
    #include<string>
    #include<cmath>
    #include<sstream>
    using namespace std;
    typedef long long ll;
    const double pi=acos(-1.0);
    const int eps=1e-10;
    const int mod=1e9+7;
    const int INF=0x3f3f3f3f;//int2147483647//ll9e18//unsigned ll 1e19
    const int maxn=500005;
    int a[maxn];
    int ts[maxn << 2],tl[maxn << 2];
    
    
    void build(int p,int l,int r)
    {
        tl[p] = 0;
        if(l == r)
        {
            ts[p] = a[l];
            return;
        }
        int mid = (l + r) / 2;
        build(p * 2,l,mid);
        build(p * 2 + 1,mid + 1,r);
        ts[p] = ts[p * 2] + ts[p * 2 + 1];
        return;
    }
    
    void pushdown(int p,int l,int r)
    {
        int mid = (l + r) / 2;
    
        ts[p *2] += tl[p] * (mid - l + 1);
        ts[p * 2 + 1] += tl[p] * (r - mid); 
        tl[p * 2] += tl[p];
        tl[p * 2 + 1] += tl[p];
        tl[p] = 0;
        return;
    }
    
    void updata(int p,int l,int r,int x,int y,ll k)
    {
        if(l > y || r < x)return;
        if( x <= l && y >= r)
        {
            ts[p] += k * (l - r + 1);
            tl[p] += k;
            return;
        }
        pushdown(p,l,r);
        int mid = (l + r) / 2;
        updata(2 * p, l,mid,x,y,k);
        updata(2 * p + 1,mid + 1,r,x,y,k);
        ts[p] = (ts[p * 2] + ts[p * 2 + 1]);
        return;
    }
    
    //error 
    ll query(int p,int l,int r,int x,int y) 
    {
        if(x > r || y < l)return 0;
        if(x <= l && y >= r)return ts[p];
        pushdown(p,l,r);
        int mid = (l + r) / 2;
        return (query(2 * p,l,mid,x,y)+query(2 * p + 1,mid + 1,r,x,y));
    }
    
    int n,m;
    int main()
    {
        scanf("%d%d",&n,&m);
        for(int i = 1;i <= n;i++)
        {
            scanf("%d",&a[i]);
        }
        build(1,1,n);
        while(m--)
        {
            int index,x,y;
            ll k;
            scanf("%d",&index);
            if(index == 1)
            {
                scanf("%d%d%lld",&x,&y,&k);
                updata(1,1,n,x,y,k);
            }
            else
            {
                scanf("%d",&x);
                printf("%lld
    ",query(1,1,n,x,x));
    
            }
    
        }
        return 0;
    }
    View Code

    嘻嘻

  • 相关阅读:
    【转】IDEA2019.1.3版本破解
    Docker部署Vue
    Docker使用
    MySql触发器
    JVM 理论基础目录(待更新,系列完全写完后会统一整理好)
    JVM 5 JAVA 垃圾回收机制
    JVM 运行时数据区:程序计数器、Java 虚拟机栈和本地方法栈,方法区、堆以及直接内存
    JVM 整体流程介绍
    JVM 入门指南
    Linux 常用命令(根据自己的理解随时更新)
  • 原文地址:https://www.cnblogs.com/lanclot-/p/Lancelot.html
Copyright © 2011-2022 走看看