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

    希望大家都可以越来越好

    树状数组关键在于数组元素下标之间的二进制关系用这个来高效的求和以及更新单个元素的值

    树状数组基础模板

    #include<bits/stdc++.h>
    using namespace std;
    const int N=1e5+5;
    int a[N];
    int tree[N];
    int n,m;
    int lowbit(int x)  //x二进制的最后一个1
    {
        return x&(-x);
    }
    void add (int x, int d)  //单点修改
    {
        while(x<=n)
        {
            tree[x]+=d;
            x+=lowbit(x);
        }
    }
    int qiuhe (int x)  //求和
    {
        int ans=0;
        while(x)
        {
            ans+=tree[x];
            x-=lowbit(x);
        }
        return ans;
    }
    int main()
    {
    
         cin>>n>>m;
         for(int i=1;i<=n;i++)
         {
             cin>>a[i];
             add(i,a[i]);
         }
         string s;
         while(m--)
         {
             int l,r,x;
              cin>>s;
             if(s=="Q")  //区间求和
             {
                 cin>>l>>r;
                  cout<<qiuhe(r)-qiuhe(l-1)<<endl;
             }
             else   //单点修改
             {
                 cin>>l>>x;
                  add(l,x);
             }
         }
    }
    View Code

    树状数组可以高效的求出一段区间的和,但是无法高效的修改一个区间内所有元素的值,用for来进行单点修改会超时当然可以直接使用线段树做

    例题:

    TOJ-

    描述

    给定n个整数,有两个操作:

    (1)给某个区间中的每个数增加一个值;

    (2)查询某个区间的和。

    输入

    第一行包括两个正整数n和q(1<=n, q<=100000),分别为序列的长度和操作次数;

    第二行包含n个整数,a1, a2, ... , an,-1000000000 ≤ ai ≤ 1000000000;

    接下来又q行,每行为以下操作之一:

    (1)更新,C i, j x: 将 x加到元素ai, ai+1, ... , aj中,其中-10000 ≤ x ≤ 10000;
    (2)查询,Q i j:求元素ai, ai+1, ... , aj的和。

    输出

    针对每次查询操作,输出结果值。

    样例输入

    10 5
    1 2 3 4 5 6 7 8 9 10
    Q 4 4
    Q 1 10
    Q 2 4
    C 3 6 3
    Q 2 4

    样例输出

    4
    55
    9
    15

    一个树状数组无法高效的更改一个区间内的元素,所以我们使用两个树状数组 tree1[],tree2[],在区间[L,R]加上x可看作

    在tree1的L位置加上-x*(L-1),R+1位置加上x*R

    在tree2的L位置加上x,R+1位置加上-x;

    sum=qiuhe(tree1,R)-qiuhe(tree1,L-1)+qiuhe(tree2,R)*R-qiuhe(tree2,L-1)*(L-1)

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    const int N=1e5+5;
    int a[N];
    ll tree1[N],tree2[N];
    int n,m;
    int lowbit(int x)
    {
        return x&(-x);
    }
    void add (ll *tree,int x,int d)
    {
        while(x<=n)
        {
            tree[x]+=d;
            x+=lowbit(x);
        }
    }
    ll qiuhe (ll *tree, int x)
    {
        ll ans=0;
        while(x)
        {
            ans+=tree[x];
            x-=lowbit(x);
        }
        return ans;
    }
    int main()
    {
         ios::sync_with_stdio(false);
         cin>>n>>m;
         for(int i=1;i<=n;i++)
         {
             cin>>a[i];
             add(tree1,i,a[i]);
         }
         string s;
         while(m--)
         {
             ll l,r,x;
             cin>>s;
             if(s=="Q")
             {
                 cin>>l>>r;
                 ll res=0;
                 res+=qiuhe(tree1,r)+qiuhe(tree2,r)*r;
                 res-=qiuhe(tree1,l-1)+qiuhe(tree2,l-1)*(l-1);
                 cout<<res<<endl;
             }
             else
             {
                 cin>>l>>r>>x;
                 add(tree1,l,-x*(l-1));
                 add(tree2,l,x);
                 add(tree1,r+1,x*r);
                 add(tree2,r+1,-x);
             }
         }
    }
    View Code

    TOJ-

    描述

    n 个小朋友站成一排。现在要把他们按身高从低到高的顺序排列,但是每次只能交换位置相邻的两个小朋友。
    每个小朋友都有一个不高兴的程度。开始的时候,所有小朋友的不高兴程度都是0。
    如果某个小朋友第一次被要求交换,则他的不高兴程度增加1,如果第二次要求他交换,则他的不高兴程度增加2(即不高兴程度为3),依次类推。当要求某个小朋友第k次交换时,他的不高兴程度增加k。
    请问,要让所有小朋友按从低到高排队,他们的不高兴程度之和最小是多少。
    如果有两个小朋友身高一样,则他们谁站在谁前面是没有关系的。

    输入

    输入的第一行包含一个整数n,表示小朋友的个数。
    第二行包含 n 个整数 H1 H2 … Hn,分别表示每个小朋友的身高。

    输出

    输出一行,包含一个整数,表示小朋友的不高兴程度和的最小值。

    样例输入

    3
    3 2 1

    样例输出

    9

    提示

    样例说明

      首先交换身高为3和2的小朋友,再交换身高为3和1的小朋友,再交换身高为2和1的小朋友,每个小朋友的不高兴程度都是3,总和为9。

    数据规模和约定

      对于10%的数据, 1<=n<=10;
      对于30%的数据, 1<=n<=1000;
      对于50%的数据, 1<=n<=10000;
      对于100%的数据,1<=n<=100000,0<=Hi<=1000000。

    耐心度的值取决于小朋友之前有几个比他高的后面有几个比他矮的矮的,可以利用树状数组求和解决 ,耐心度的计算为等差数列

    #include<bits/stdc++.h>
    using namespace std;
    const int N=1e5+10;
    const int M=1e6+10;
    int a[N];
    int b[N],tree[M];
    int lowbit(int x)
    {
        return x&(-x);
    }
    int qiuhe(int x)
    {
        int ans=0;
        while(x)
        {
            ans+=tree[x];
            x-=lowbit(x);
        }
        return ans;
    }
    void add(int d,int x)
    {
        while(x<=M)
        {
            tree[x]+=d;
            x+=lowbit(x);
        }
        return ;
    }
    int main()
    {
        ios::sync_with_stdio(false);
        int n,i;
        cin>>n;
        memset(b,0,sizeof(b));
        memset(tree,0,sizeof(tree));
        for(i=1;i<=n;i++)
        {
           cin>>a[i];
           add(1,a[i]+1);
           b[i]=i-qiuhe(a[i])-1;
           b[i]-=qiuhe(a[i]+1)-qiuhe(a[i])-1;//去掉身高一样的
        }
        memset(tree,0,sizeof(tree));
        for(i=n;i>=1;i--)
        {
            add(1,a[i]+1);
            b[i]+=qiuhe(a[i]);
        }
        long long ans1=0;
        for(i=1;i<=n;i++)
        {
            ans1+=(long long)b[i]*(b[i]+1)/2;
        }
        cout<<ans1<<endl;
        return 0;
    }
    View Code

    运用上一题的方法可以解决一些区间问题,只需要将区间的一个端点排序另一个端点按照上一题的树状数组做法做

    TOJ-

    描述

    Farmer John's cows have discovered that the clover growing along the ridge of the hill (which we can think of as a one-dimensional number line) in his field is particularly good. 

    Farmer John has N cows (we number the cows from 1 to N). Each of Farmer John's N cows has a range of clover that she particularly likes (these ranges might overlap). The ranges are defined by a closed interval [S,E]. 

    But some cows are strong and some are weak. Given two cows: cowi and cowj, their favourite clover range is [Si, Ei] and [Sj, Ej]. If Si <= Sj and Ej <= Ei and Ei - Si > Ej - Sj, we say that cowi is stronger than cowj

    For each cow, how many cows are stronger than her? Farmer John needs your help!

    输入

    The input contains multiple test cases. 
    For each test case, the first line is an integer N (1 <= N <= 105), which is the number of cows. Then come N lines, the i-th of which contains two integers: S and E(0 <= S < E <= 105) specifying the start end location respectively of a range preferred by some cow. Locations are given as distance from the start of the ridge. 

    The end of the input contains a single 0.

    输出

    For each test case, output one line containing n space-separated integers, the i-th of which specifying the number of cows that are stronger than cowi.

    样例输入

    3
    1 2
    0 3
    3 4
    0

    样例输出

     1 0 0

     

    提示

    Huge input and output,scanf and printf is recommended.
     
    #include<bits/stdc++.h>
    using namespace std;
    const int N=1e5+5;
    int c[N];
    int tree[N];
    int n,m;
    struct jilu
    {
        int l,r;
        int id;
    }cow[N];
    bool cmp(jilu a,jilu b)
    {
        if(a.r==b.r) return a.l<b.l;
        return a.r>b.r;
    }
    int lowbit(int x)
    {
        return x&(-x);
    }
    void add (int x,int d)
    {
        while(x<=N)
        {
            tree[x]+=d;
            x+=lowbit(x);
        }
    }
    int qiuhe (int x)
    {
        int ans=0;
        while(x)
        {
            ans+=tree[x];
            x-=lowbit(x);
        }
        return ans;
    }
    int main()
    {
         ios::sync_with_stdio(false);
         while(cin>>n)
         {
             if(n==0) break;
             memset(c,0,sizeof(c));
             memset(tree,0,sizeof(tree));
             for(int i=1;i<=n;i++)
             {
                 cin>>cow[i].l>>cow[i].r;
                 cow[i].l++;
                 cow[i].id=i;
             }
             sort(cow+1,cow+n+1,cmp);
            for(int i=1;i<=n;i++)
            {
                if(cow[i].l==cow[i-1].l&&cow[i].r==cow[i-1].r)  //避免相同区间加入排序过后只要不相同的都覆盖
                    c[cow[i].id]=c[cow[i-1].id];
                else c[cow[i].id]=qiuhe(cow[i].l);
                add(cow[i].l,1);
            }
             for(int i=1;i<=n;i++)
             {
                 if(i==1)
                 cout<<c[i];
                 else
                cout<<" "<<c[i];
             }
              cout<<endl;
         }
    View Code

     

  • 相关阅读:
    使用私有api实现自己的iphone桌面,并根据app的使用次数对app排序
    坐标系的属性
    带坐标轴的几何画板
    空间几何体的直观图matlab
    设置npm的registry
    (原创)机器学习之numpy库中常用的函数介绍(一)
    (原创)交叉编译 tesseract
    (原创)计算机视觉之数学原理-基础篇
    (原创)nRF51 DFU 初始化包介绍及生成工具
    (原创)使用nRF51822/nRF51422创建一个简单的BLE应用 ---入门实例手册(中文)之五
  • 原文地址:https://www.cnblogs.com/xbqdsjh/p/11421358.html
Copyright © 2011-2022 走看看