题意:
n(5*10^5)个不同的数字组成的序列a 寻找满足如下约束条件的数字组数: i1<i2<i3<i4 && ai1<ai2 && ai3<ai4
思路:
明显考察的是nlogn的算法 我们发现其实ai1和ai2可以放在一起考虑 同理ai3和ai4 这两组并没有相互影响
我们来看答案是怎么构成的 假设枚举i3的位置 那么我们希望知道“i3后面有几个数大于ai3” 这个可以通过树状数组处理
同理假设我们知道i2也希望知道“i2前面有几个数小于ai2” 这个也可以树状数组
那么再利用i3>i2 则答案就可以表示为 sum( num(>ai3) * sum( num(<ai2) ) )
代码:
#include<cstdio>
#include<iostream>
#include<cstring>
#include<string>
#include<algorithm>
#include<map>
#include<set>
#include<vector>
#include<queue>
#include<cstdlib>
#include<ctime>
#include<cmath>
using namespace std;
typedef long long LL;
#define N 50000
#define lowbit(x) (x&(-x))
inline void scand(int &ret) {
char c;
ret = 0;
while ((c = getchar()) < '0' || c > '9')
;
while (c >= '0' && c <= '9')
ret = ret * 10 + (c - '0'), c = getchar();
}
int t, n;
int c[N + 10], d[N + 10], g[N + 10];
LL ans;
void add(int f[], int x, int key) {
while (x <= N) {
f[x] += key;
x += lowbit(x);
}
}
int sum(int f[], int x) {
int res = 0;
while (x) {
res += f[x];
x -= lowbit(x);
}
return res;
}
struct node {
int val, id;
} nd[N + 10];
bool cmp1(node fa, node fb) {
return fa.val < fb.val;
}
bool cmp2(node fa, node fb) {
return fa.id < fb.id;
}
int main() {
scand(t);
while (t--) {
scand(n);
for (int i = 1; i <= n; i++) {
scand(nd[i].val);
nd[i].id = i;
}
sort(nd + 1, nd + n + 1, cmp1);
memset(c, 0, sizeof (c));
memset(d, 0, sizeof (d));
for (int i = 1; i <= n; i++) {
int tmp = sum(c, nd[i].id);
add(c, nd[i].id, 1);
add(d, nd[i].id, tmp);
g[nd[i].id] = sum(c, nd[i].id - 1);
}
sort(nd + 1, nd + n + 1, cmp2);
ans = 0;
for (int i = 3; i <= n; i++) {
int tmp = nd[i].val - 1;
tmp = n - i - (tmp - g[i]);
ans += (LL) (tmp) * sum(d, i - 1);
}
printf("%I64d\n", ans);
}
return 0;
}原文:http://blog.csdn.net/houserabbit/article/details/42062267