ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

Luogu P3149 排序(树状数组、前缀和)

2021-01-26 17:03:59  阅读:150  来源: 互联网

标签:val 树状 P3149 Luogu LL atot 贡献 ta 逆序


P3149

思路:

稍微模拟一下就能发现,每一次的操作其实就是将“第1~第k个位置上的值”的逆序对的贡献清零。

那么我们先对数据离散化后用树状数组求出每个位置上的值能贡献的逆序对,并使用前缀和加速逆序对的区间求值。

值得注意的一点是按照从大到小的顺序去修改树状数组就可以计算出每个位置上的值贡献的逆序对。

Code:
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const LL N = 300010;

struct Node {
	LL val, pos; //pos为第几个出现
	LL opt; //该点贡献的逆序对
	bool operator<(const Node& t) const {
		if (val == t.val) return pos < t.pos;
		else return val < t.val;
	}
} a[N];
LL tr[N], r[N], ta[N], atot;
LL n, m, ans, trans[N]/*第i个位置上的数是几*/;
LL sum[N];

void update(LL x, LL k) {
	for (; x <= n; x += x & -x)
		tr[x] += k;
}

LL query(LL x) {
	LL res = 0;
	for (; x; x -= x & -x) 
		res += tr[x];
	return res;
}

int main() {
	ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
	cin >> n >> m;
	for (LL i = 1; i <= n; i++) {
		cin >> a[i].val;
		a[i].pos = i;
		ta[++atot] = a[i].val;
	}

	sort(ta + 1, ta + 1 + atot);
	atot = unique(ta + 1, ta + 1 + atot) - ta - 1; //atot为离散后的表长

	for (LL i = n; i >= 1; i--) { //倒着求就可以算出每个点所产生的逆序对的数量
		a[i].val = lower_bound(ta + 1, ta + 1 + atot, a[i].val) - ta; //离散化,即原来的数->原来的数是第几小的
		a[i].opt = query(a[i].val - 1); //在他之后还比他小的 即 a[i].val贡献的逆序对数量
		ans += a[i].opt;
		update(a[i].val, 1);
	}

	sort(a + 1, a + 1 + n); //求排序后的前缀和。因为要减掉的是小于等于第k个位置的值的逆序对总贡献
	for (LL i = 1; i <= n; i++) {
		sum[i] = sum[i - 1] + a[i].opt;
		trans[a[i].pos] = i; //[原来的数的位置]->在排序后的位置
	}

	cout << ans << endl;
	LL maxval = 0, nowopt = 0;
	for (LL i = 1; i <= m; i++) {
		LL k; cin >> k;
		if (a[trans[k]].val >= maxval) {
			nowopt = sum[n] - sum[trans[k]];
			cout << nowopt << endl;
			maxval = a[trans[k]].val;
		} else { //这一段已经排过序,不再贡献逆序对
			cout << nowopt << endl;
		}
	}
	return 0;
}

/*
4 2
1 4 2 3
4
3

5 2
2 6 3 5 4
3
4

*/

标签:val,树状,P3149,Luogu,LL,atot,贡献,ta,逆序
来源: https://www.cnblogs.com/Nepenthe8/p/14331367.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有