zoukankan      html  css  js  c++  java
  • 树状数组-练习题

    楼兰图腾

    题目

    https://ac.nowcoder.com/acm/contest/1032/A

    题解

    涉及到的是树状数组找出逆序对的知识,步骤如下:

    ①倒叙扫描序列,wright记录右侧有多少小于他,vright记录右侧有多少大于它的数

    ②正序扫描序列,求出每个a[i]左侧有几个数比他小,乘上wright[i],累加后就是^的个数;求出左侧有多少大于它的,乘上vright[i],累加后就是v的个数

    代码

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    const int N=2e5+10;
    int c[N];
    int a[N];
    int n;
    int vright[N];
    int wright[N];
    
    int lowbit(int x)
    {
        return x&-x;
    }
    
    int ask(int x)
    {
        int ans=0;
        for(;x;x-=lowbit(x))
            ans+=c[x];
        return ans;
    }
    
    void add(int x,int y)
    {
        for(;x<N;x+=lowbit(x))
            c[x]+=y;
    }
    
    int main()
    {
        int i,j;
        cin>>n;
        for(i=1;i<=n;i++)
        {
            cin>>a[i];
        }
        ll vans=0;
        ll wans=0;
        for(i=n;i;i--)
        {
            wright[i]=ask(a[i]-1);//右侧有多少小于他的
            vright[i]=ask(n)-ask(a[i]);//右侧有多少大于他的
            add(a[i],1);
        }
        memset(c,0,sizeof(c));
        for(i=1;i<=n;i++)
        {
            wans+=(ll)wright[i]*ask(a[i]-1);//左侧有多少小于的
            vans+=(ll)vright[i]*(ask(n)-ask(a[i]));//左侧有多少大于的
            add(a[i],1);
        }
        cout<<vans<<" "<<wans<<endl;
        return 0;
    }

    A Tiny Problem with intergers

    题目

    https://ac.nowcoder.com/acm/contest/1032/B

    题解

    用树状数组做区间增加,而他支持“单点增加”和“单点查询”,如何做区间增加呢?

    用差分的思想来做:例如C l r d

    1.把b[l]加上d

    2.把b[r+1]-d;

    就可以做到只增加[l,r],单点求和即所求:a[x]+ask(x)

    代码

    #include<bits/stdc++.h>
    using namespace std;
    
    const int N=1e5+10;
    int a[N],b[N];
    
    int lowbit(int x)
    {
        return x&-x;
    }
    
    int ask(int x)
    {
        int ans=0;
        for(;x;x-=lowbit(x))
        {
            ans+=b[x];
        }
        return ans;
    }
    
    void add(int x,int y)
    {
        for(;x<N;x+=lowbit(x))
            b[x]+=y;
    }
    
    int main()
    {
        int i,j,n,q;
        cin>>n>>q;
        for(i=1;i<=n;i++)
            cin>>a[i];
        while(q--)
        {
            char c;
            int l,r,d;
            cin>>c;
            if(c=='C')
            {
                cin>>l>>r>>d;
                add(l,d);
                add(r+1,-d);
            }
            else
            {
                cin>>l;
                cout<<a[l]+ask(l)<<endl;
            }
        }
        return 0;
    }

    A Simple Problem with Integers

    题目

    https://ac.nowcoder.com/acm/contest/1032/C

    题解

    此题用树状数组求区间和,这下可有点子难度:

     代码

    #include<bits/stdc++.h>
    using namespace std;
    const int N=1e5+10;
    int a[N],n,m;
    typedef long long ll;
    ll c[2][N],sum[N];
    
    int lowbit(int x)
    {
        return x&-x;
    }
    
    ll ask(int k,int x)
    {
        ll ans=0;
        for(;x;x-=lowbit(x))
            ans+=c[k][x];
        return ans;
    }
    
    void add(int k,int x,int y)
    {
        for(;x<=n;x+=lowbit(x))
            c[k][x]+=y;
    }
    
    int main()
    {
        int i,j;
        cin>>n>>m;
        for(i=1;i<=n;i++)
        {
            cin>>a[i];
            sum[i]=sum[i-1]+a[i];
        }
        while(m--)
        {
            char s;
            int a,b,c;
            cin>>s;
            if(s=='C')
            {
                cin>>a>>b>>c;
                add(0,a,c);
                add(0,b+1,-c);
                add(1,a,a*c);
                add(1,b+1,-(b+1)*c);
            }
            else
            {
                cin>>a>>b;
                ll ans=sum[b]+(b+1)*ask(0,b)-ask(1,b);
                ans-=sum[a-1]+a*ask(0,a-1)-ask(1,a-1);
                cout<<ans<<endl;
            }
        }
    
        return 0;
    }

    Lost Cows

    题目

    https://ac.nowcoder.com/acm/contest/1032/D

    题解

    建立一个全1数组b,然后从n到1倒叙遍历每个Ai,对每个Ai执行一下两个操作:

    1.查询b数组中第Ai+1个1在什么位置,只个位置就是第i头牛的身高Hi

    2.把b[Hi]减1(从1到0)

    用树状数组维护前缀和,每次查询二分时的答案,通过ask(mid)即可得到前面有多少个1,与t比较大小,即可确定二分的边界(注意:要找前缀和中第一个符合要求的下标

    代码

    #include<bits/stdc++.h>
    using namespace std;
    const int N=8e4+10;
    int a[N];
    int b[N];
    int n;
    
    int lowbit(int x)
    {
        return x&-x;
    }
    
    void add(int x,int y)
    {
        for(;x<=n;x+=lowbit(x))
            b[x]+=y;
    }
    
    int ask(int x)
    {
        int ans=0;
        for(;x;x-=lowbit(x))
            ans+=b[x];
        return ans;
    }
    
    
    int main()
    {
        int i,j;
        cin>>n;
        for(i=1;i<=n-1;i++)
        {
            cin>>a[i];
            add(i,1);
        }
        add(n,1);
        int ans[N];
        int len=n;
        for(i=n-1;i>=0;i--)
        {
            int t=a[i]+1;
            int l=1,r=n;
            int mid;
            while(l<r)
            {
                mid=(l+r)/2;
                int res=ask(mid);
                if(res<t)
                    l=mid+1;
                else
                    r=mid;
            }
            ans[len--]=l;
            add(l,-1);
        }
        for(i=1;i<=n;i++)
            cout<<ans[i]<<endl;
    
        return 0;
    }
  • 相关阅读:
    通讯录封装实现
    简单通讯录的实现 main..h .m文件全部
    iOS 开发 OC编程 字典和集合 排序方法
    iOS 开发 OC编程 数组冒泡排序.图书管理
    iOS 开发 OC编程 属性和字符串练习
    iOS 开发 OC编程 属性和字符串
    iOS 开发 OC编程 便利构造器以及初始化方法
    iOS 开发 OC编程 方法的书写
    IOS 开发 OC编程 类和对象
    iOS 开发 c语言阶段考试题
  • 原文地址:https://www.cnblogs.com/xiaofengzai/p/14567547.html
Copyright © 2011-2022 走看看