树状数组..

操作1:遍历index的上一个结点和下一个结点的媒介

int lowbits(int index)
{
    return index & (-index);
}加个循环就好

操作二:修改每一个父亲结点由于元素a[i]而要修改的值

void add(int index, int y)
{
    for (int i = index; i <= n; i += lowbits(i))
    {
        c[i] += y;
    }
}

操作三:算出前缀和

int getsum(int index)
{
    int ans = 0;
    for (int i = index; i >= 1; i -= lowbits(i))
    {
        ans += c[i];
    }
    return ans;
}

lowbits的具体可以这样子操作的原因去草稿纸演算下就好
看图

板子排兵布阵hdu 链接:http://acm.hdu.edu.cn/showproblem.php?pid=1166

#include <bits/stdc++.h>
using namespace std;
#define debug(x) cout << #x << " == " << x << endl;
#define INF 0x3f3f3f
#define ll long long
const ll int MAX_N = 5e5 + 10;
int a[MAX_N] = {0};
int c[MAX_N] = {0};
int n;
int lowbits(int index)
{
    return index & (-index);
}
void add(int index, int y)
{
    for (int i = index; i <= n; i += lowbits(i))
    {
        c[i] += y;
    }
}
int getsum(int index)
{
    int ans = 0;
    for (int i = index; i >= 1; i -= lowbits(i))
    {
        ans += c[i];
    }
    return ans;
}
int main()
{
    int t;
    scanf("%d", &t);
    int cas = 0;
    while (t--)
    {
        cas++;
        printf("Case %d:\n", cas);
        scanf("%d", &n);
        memset(c, 0, sizeof(c));
        for (int i = 1; i <= n; i++)
        {
            scanf("%d", &a[i]);
            add(i, a[i]);
        }
        string cz;
        while (cin >> cz)
        {
            if (cz == "End")
            {
                break;
            }
            else if (cz == "Query")
            {
                int l, r;
                scanf("%d %d", &l, &r);
                printf("%d\n", getsum(r) - getsum(l - 1));
            }
            else if (cz == "Add")
            {
                int index, value;
                scanf("%d %d", &index, &value);
                add(index, value);
            }
            else if (cz == "Sub")
            {
                int index, value;
                scanf("%d %d", &index, &value);
                add(index, -value);
            }
        }
    }
    system("pause");
    return 0;
}

逆序对

#include <bits/stdc++.h>
using namespace std;
#define debug(x) cout << #x << " == " << x << endl;
#define INF 0x3f3f3f
#define ll long long
const ll int MAX_N = 5e5 + 10;
int a[MAX_N] = {0};
int b[MAX_N] = {0};
int c[MAX_N] = {0};///记录的是区间内存在的数有多少个
int n;
int lowbits(int index)
{
    return index & (-index);
}
bool cmp(int x, int y)
{
    if (a[x] != a[y])
        return a[x] > a[y];
     ///求a的逆序对就相当于是求a(降序排序)逆向排序后的下标b正序对
     ///例如 1 2 3 对应下标 1 2 3
     ///排序后 a:3 2 1 b:3 2 1 正序对为0
     ///之所以这样子做是为了离散化处理 如果直接利用a的区间来求,可能会导致范围很大
     ///浪费很多空间 利用下标可以有效表示a[i],a[j]的大小关系也不会浪费区间
    else
        return x > y;
}
void add(int x)
{
    for (int i = x; i <= n; i += lowbits(i))
    {
        c[i]++;///所有 包含x这个数 的区间的存在的数加一
    }
}
int getsum(int x)
{
    int ans = 0;
    for (int i = x; i >= 1; i -= lowbits(i))
    {
        ans += c[i];
        ///在下标x之前 在1~x-1下标有多少被已经记录了 
        ///求出右对位 b[index],范围为1~index-1 所有的正序对
    }
    return ans;
}
int main()
{
    scanf("%d", &n);
    for (int i = 1; i <= n; i++)
    {
        scanf("%d", &a[i]);
        b[i] = i;
    }
    sort(b + 1, b + 1 + n, cmp);
    ll tot = 0;
    for (int i = 1; i <= n; i++)
    {

        add(b[i]);
        tot += getsum(b[i] - 1);
    }
    printf("%lld\n", tot);
    system("pause");
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值