刷题笔记-树状数组

动态求连续区间和 -模板题

代码:

#include <cstdio>
#include <cstring>
#include <iostream>

using namespace std;

const int N = 100010;
int s[N];
int w[N];
int n , m;
int lowbit(int x)
{
    return x & -x;
}
int getSum(int x)
{
    int res = 0;
    for(int i = x; i > 0; i -= lowbit(i))
        res += s[i];
    return res;
}
void add(int x,int a)
{
    for(int i = x; i <= n; i += lowbit(i))
        s[i] += a;
}

int main(void)
{
    cin >> n >> m;
    for(int i = 1; i <= n; i++) 
    {
        scanf("%d", &w[i]);
        add(i , w[i]);
    }
    
    int k ,a ,b;
    while(m -- )
    {
        scanf("%d%d%d",&k , &a , &b);
        if(k == 0) printf("%d\n",getSum(b) - getSum(a - 1));
        else add(a , b);
    }
    
    return 0;
}

数星星

思路:

树状数组用来保存每个x坐标上星星的总数,那么每一颗新星(x,y)的等级为getSum(x)
然后再将这一颗新星加入树状数组add(x,1);

代码:

#include <cstdio>
#include <cstring>
#include <iostream>

using namespace std;

const int N = 32010;
int s[N];
int ans[N];
int lowbit(int x)
{
    return x & -x;
}
int getSum(int x)
{
    int res = 0;
    for(int i = x; i > 0; i -= lowbit(i))
        res += s[i];
    return res;
}
void add(int x,int a)
{
    for(int i = x; i <= 32001; i += lowbit(i))
        s[i] += a;
}

int main(void)
{
    int n;
    cin >> n;
    for(int i = 0; i < n; i++)
    {
        int x,y;
        cin >> x >> y;  x++;
        int tmp =  getSum(x);
        ans[tmp]++;
        add(x,1);
    }
    for(int i = 0; i < n; i++)
        cout << ans[i] << endl;
    
    return 0;
}

小朋友排队

思路:

1.最开始想这是一个排序题,和逆序对的数量那一题类似,实际上是一个排序背景下求动态前缀和的问题。
2.假设序列中逆序对的个数是K,那么交换相邻两个元素最多会使逆序对的数量减少1,因为这种交换只会影响这两个元素,它们相对其他元素的位置相当于没有变化。

  • 说明至少交换K次,才能消除所有的逆序对
    3.冒泡排序是一种交换相邻两个元素的排序,且每一次交换必然使逆序对的个数减一,所以采用冒泡的方式进行排序,可以只交换K次,就能消除所有逆序对
  • 说明最优方案一定是交换了K次,且交换的规则类似于冒泡排序
    4.在冒泡排序中,考虑一个一般元素,发现它的交换次数:在它前面且比它大的元素个数 + 在它后面且比它小的元素个数、
  • 所以本质上,是要我们分别求序列的动态前向&后向前缀和
    5.使用归并排序也可以做,只是难在怎样记录每一个元素的交换次数,因为在排序中一个元素的位置是一直在变化的,所以不能用下标,且元素的值不唯一,也不能使用值作为下标。

代码:

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;

typedef long long LL;

const int N = 1000010;

int a[N],s[N],val[N];
int n;
LL ans;
int lowbit(int x)
{
    return x & -x;
}
void add (int x,int a)
{
    for(int i = x; i < N; i += lowbit(i))
        s[i] += a;
}
int getSum(int x)
{
    int res = 0;
    for(int i = x; i > 0; i -= lowbit(i))
        res += s[i];
    
    return res;
    
}

int main(void)
{
    cin >> n;
    for(int i = 0; i < n; i++)
    {
        scanf("%d",&a[i]);
        a[i]++;
        //求在第i个元素之前,且比它大的元素个数
        add(a[i], 1);
        val[i] = getSum(N - 1) - getSum(a[i]);
    }
    memset(s,0,sizeof(s));
    
    for(int i = n-1; i >= 0; i--)
    {
        //求在第i个元素之后,且比它小的元素个数
        add(a[i], 1);
        val[i] += getSum(a[i] - 1);
    }
    
    for(int i = 0; i < n; i++)
        ans += (LL)(1 + val[i])* val[i] / 2;
    
    cout << ans << endl;
    
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/zy200128/p/12674413.html
今日推荐