洛谷 P5677 [GZOI2017]配对统计

原题链接
首先把配对数在原数组中的下标对存起来,这时候\(c[i].fr\)有可能大于\(c[i].se\),遍历一遍交换,方便后续操作
然后把\(c[i]\)按照左端点排序,把所有询问离线下来,按照左端点从小到大排序
统计答案:统计每个\(c[i]\)对答案的贡献,当遍历到\(c[k]\)时,把所有左端点小于等于\(c[k].fr\)的询问加入树状数组(新增的值为询问的编号),这时候左端点肯定满足,只要看右端点是否包含\(c[k].se\)即可,所以\(sum[n] - sum[c[k].se - 1]\)即为每个数对的贡献

#include<bits/stdc++.h>
using namespace std;

#define fr first
#define se second
#define et0 exit(0);
#define rep(i, a, b) for(int i = (int)(a); i <= (int)(b); i ++)
#define rrep(i, a, b) for(int i = (int)(a); i >= (int)(b); i --)
#define IO ios::sync_with_stdio(false),cin.tie(0);

typedef long long LL;
typedef pair<int, int> PII;
typedef pair<PII, int> PPI;
typedef pair<LL, LL> PLL;
typedef unsigned long long ULL;

const int INF = 0X3f3f3f3f, N = 3e5 + 10, MOD = 1e9 + 7;
const double eps = 1e-7, pi = acos(-1);

int n, m;
int a[N], b[N];
LL tr[N];
PII c[N];

map<int, int> mp;

int lowbit(int x){
    return x & -x;
}

void insert(int x, int c){
    for(int i = x; i <= n; i += lowbit(i)) tr[i] += c;
}

LL query(int x){
    LL res = 0;
    for(int i = x; i >= 1; i -= lowbit(i)) res += tr[i];
    return res;
}

bool cmp(PII &x, PII &y) {
	if (x.fr == y.fr) return x.se < y.se;
	return x.fr < y.fr;
}

bool _cmp(PPI &x, PPI &y) {
	if (x.fr.fr == y.fr.fr) return x.fr.se < y.fr.se;
	return x.fr.fr < y.fr.fr;
}

void work() {
	cin >> n >> m;
	if (n == 1) {
		cout << 0 << endl;
		return;
	}
	rep (i, 1, n) cin >> a[i], mp[a[i]] = i, b[i] = a[i];
	sort(b + 1, b + 1 + n);
	vector<PII> c(2 * n + 1);
	vector<PPI> q(m + 1);
	int cnt = 0;
	rep (i, 1, n) {
		if (i == 1) c[++cnt].fr = mp[b[i]], c[cnt].se = mp[b[i + 1]];
		else if (i == n) c[++cnt].fr = mp[b[i - 1]], c[cnt].se = mp[b[i]];
		else {
			int x = abs(b[i] - b[i - 1]), y = abs(b[i + 1] - b[i]), z = min(x, y);
			if (x == z) c[++cnt].fr = mp[b[i - 1]], c[cnt].se = mp[b[i]];
			if (y == z) c[++cnt].fr = mp[b[i]], c[cnt].se = mp[b[i + 1]];
		}
	}
	rep (i, 1, cnt) if (c[i].fr > c[i].se) swap(c[i].fr, c[i].se);
	sort(c.begin() + 1, c.begin() + 1 + cnt, cmp);
	
	rep (i, 1, m) cin >> q[i].fr.fr >> q[i].fr.se, q[i].se = i;
	sort(q.begin() + 1, q.begin() + 1 + m, _cmp);
	
	int pos = 1;
	LL res = 0;
	rep (i, 1, cnt) {
		while (pos <= m && q[pos].fr.fr <= c[i].fr) {
			insert(q[pos].fr.se, q[pos].se);
			pos++;
		}
		res += query(n) - query(c[i].se - 1);
	}
	cout << res << endl;
}

signed main() {
	IO

	int test = 1;

	while (test--) {
		work();
	}

	return 0;
}
posted @ 2022-08-28 22:35  xhy666  阅读(72)  评论(0)    收藏  举报