操作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;
}