树状数组 在线处理序列中比k大的数量 T3 241. 楼兰图腾 - AcWing题库
在完成了分配任务之后,西部 来到了楼兰古城的西部。
相传很久以前这片土地上(比楼兰古城还早)生活着两个部落,一个部落崇拜尖刀(V
),一个部落崇拜铁锹(∧
),他们分别用 V
和 ∧
的形状来代表各自部落的图腾。
西部 在楼兰古城的下面发现了一幅巨大的壁画,壁画上被标记出了 个点,经测量发现这 个点的水平位置和竖直位置是两两不同的。
西部 认为这幅壁画所包含的信息与这 个点的相对位置有关,因此不妨设坐标分别为 ,其中 是 到 的一个排列。
西部 打算研究这幅壁画中包含着多少个图腾。
如果三个点 满足 且 ,则称这三个点构成 V
图腾;
如果三个点 满足 且 ,则称这三个点构成 ∧
图腾;
西部 想知道,这 个点中两个部落图腾的数目。
因此,你需要编写一个程序来求出 V
的个数和 ∧
的个数。
输入格式
第一行一个数 。
第二行是 个数,分别代表 。
输出格式
两个数,中间用空格隔开,依次为 V
的个数和 ∧
的个数。
数据范围
对于所有数据,,且输出答案不会超过 。
是 到 的一个排列。
输入样例:
5
1 5 3 2 4
输出样例:
3 4
思路
求一个序列中所有满足以下条件的数对个数:
如果三个点 满足 且 ,则称这三个点构成 V
图腾;
如果三个点 满足 且 ,则称这三个点构成 ∧
图腾;
且数据范围限制只能用 或 的算法求解, 这形式的问题通常都以中间点为依据来思考。
把所有三个点构成的数对以中间节点的横坐标为依据划分集合。则以 为中间点的 V 图腾, 其数量就是 1k大于k高度的点数量 * k+1n大于k高度的点数量。另一种图腾也同理。
故现在需要做的就是 查询1~k-1中 比 k 大的数量, 和 插入当前k值。区间查询和点修改。
代码
#include <iostream>
#include <cstring>
#include <algorithm>
#include <string>
#include <cmath>
using namespace std;
const int N = 2e5 + 10;
typedef long long LL;
int a[N], t[N];
int n;
int great[N], low[N];
int lowbit(int x)
{
return x & -x;
}
void add(int x, int c)
{
for(int i = x; i <= n; i+= lowbit(i)) t[i] += c;
}
LL sum(int x)
{
LL res = 0;
for(int i = x; i; i -= lowbit(i)) res += t[i];
return res;
}
int main()
{
cin >> n;
for(int i = 1; i <= n; i++) cin >> a[i];
for(int i = 1; i <= n; i++)
{
int y = a[i];
great[i] = sum(n) - sum(y);
low[i] = sum(y - 1);
add(a[i], 1);
}
memset(t, 0, sizeof t);
LL res1 = 0, res2 = 0;
for(int i = n; i; i--)
{
int y = a[i];
res1 += great[i] * (sum(n) - sum(y));
res2 += low[i] * sum(y - 1);
add(y, 1);
}
cout << res1 << " " << res2 << endl;
return 0;
}