[P1637] 三元上升子序列 (线段树+离散化)

【原题】

题目描述

Erwin 最近对一种叫 thair 的东西巨感兴趣。。。

在含有 nnn 个整数的序列 \(a1,a2,…,an\) 中,三个数被称作thair当且仅当 \(i<j<k\)\(ai<aj<ak\)

求一个序列中 thair 的个数。

输入格式

开始一行一个正整数\(n\),

以后一行 \(n\) 个整数 \(a1,a2,…,an\)

输出格式

一行一个整数表示 thair 的个数。

输入输出样例

输入 #1

4
2 1 3 4

输出 #1

2

输入 #2

5
1 2 2 3 4

输出 #2

7

说明/提示

样例2 解释

7个 thair 分别是:

  • 1 2 3
  • 1 2 4
  • 1 2 3
  • 1 2 4
  • 1 3 4
  • 2 3 4
  • 2 3 4

数据规模与约定

  • 对于 \(30\%\)的数据 保证 \(n≤100\)
  • 对于 \(60\%\) 的数据 保证 \(n≤2000\)
  • 对于 \(100\%\)的数据 保证 \(1≤n≤3×10^4,0≤ai<2^{63}\)

【思路】

用pair存二元个数, cnt存一元个数,不断更新,题解的乘法原理没想到,惭愧。

#include <algorithm>
#include <cmath>
#include <cstdio>
#include <cstring>
#include <list>
#include <map>
#include <iostream>
#include <iomanip>
#include <queue>
#include <set>
#include <stack>
#include <string>
#include <unordered_map>
#include <vector>
#define LL long long
#define inf 0x3f3f3f3f
#define INF 0x3f3f3f3f3f3f
#define PI 3.1415926535898
#define F first
#define S second
#define endl '\n'
#define lson  rt << 1
#define rson  rt << 1 | 1
#define f(x, y, z) for (int x = (y), __ = (z); x < __; ++x)
#define _rep(i, a, b) for (int i = (a); i <= (b); ++i)
using namespace std;

const int maxn = 3e4 + 7;
const int maxm = 1e6 + 7;
const int mod = 1e9 + 7;
int n, m;

struct node
{
	LL pair, cnt;
}tree[maxn * 4];

struct pp
{
	LL pair, cnt;
}lz[maxn * 4];

LL a[maxn], b[maxn], id[maxn];

void update(int n, int index, int L, int R, int rt) {
	if (L == R) {
		tree[rt].cnt = n;
		return;
	}
	int mid = (L + R) / 2;
	if (index <= mid) {
		update(n, index, L, mid, lson);
	}
	else {
		update(n, index, mid + 1, R, rson);
	}
	tree[rt].cnt = tree[lson].cnt + tree[rson].cnt;
}

void add(int n, int index, int L, int R, int rt)
{
	if (L == R)
	{
		tree[rt].cnt += n;
		return;
	}
	int mid = (L + R) / 2;
	if (index <= mid) add(n, index, L, mid, lson);
	else add(n, index, mid + 1, R, rson);
	tree[rt].cnt = tree[lson].cnt + tree[rson].cnt;
}

void push_down(int rt, int l, int r) {
	if (lz[rt].cnt) {
		int mid = (l + r) / 2;
		lz[lson].cnt += lz[rt].cnt;
		lz[rson].cnt += lz[rt].cnt;
		tree[lson].cnt += 1LL * (mid - l + 1) * lz[rt].cnt;
		tree[rson].cnt += 1LL * (r - mid) * lz[rt].cnt;
		lz[rt].cnt = 0;
	}
	if (lz[rt].pair)
	{
		int mid = (l + r) / 2;
		lz[lson].pair += lz[rt].pair;
		lz[rson].pair += lz[rt].pair;
		tree[lson].pair += 1LL * (mid - l + 1) * lz[rt].pair;
		tree[rson].pair += 1LL * (r - mid) * lz[rt].pair;
		lz[rt].pair = 0;
	}
}

LL query_range(int rt, int l, int r, int L, int R) {
	if (l <= L && r >= R) return tree[rt].cnt;
	push_down(rt, L, R);
	int mid = (L + R) / 2;
	LL sum = 0;
	if (mid >= l) sum += query_range(lson, l, r, L, mid);
	if (mid < r) sum += query_range(rson, l, r, mid + 1, R);
	return sum;
}
void add_pair(int n, int index, int L, int R, int rt)
{
	if (L == R)
	{
		tree[rt].pair += n;
		return;
	}
	int mid = (L + R) / 2;
	if (index <= mid) add_pair(n, index, L, mid, lson);
	else add_pair(n, index, mid + 1, R, rson);
	tree[rt].pair = tree[lson].pair + tree[rson].pair;
}

LL query_pair(int rt, int l, int r, int L, int R)
{
	if (l <= L && r >= R) return tree[rt].pair;
	push_down(rt, L, R);
	int mid = (L + R) / 2;
	LL sum = 0;
	if (mid >= l) sum += query_pair(lson, l, r, L, mid);
	if (mid < r) sum += query_pair(rson, l, r, mid + 1, R);
	return sum;
}

int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
	cin >> n;
	LL ans = 0;
	int mx = 3e4;
	_rep(i, 1, n)
	{
		cin >> a[i];
		b[i] = a[i];
	}
	sort(a + 1, a + n + 1);
	int sz = unique(a + 1, a + n + 1) - a - 1;
	mx = sz + 1;
	_rep(i, 1, n)
	{
		id[i] = lower_bound(a + 1, a + 1 + sz, b[i]) - a;
	}
	_rep(i, 1, n)
	{
		add(1, id[i], 0, mx, 1);
		ans += query_pair(1, 0, id[i] - 1, 0, mx);
		LL tmp = query_range(1, 0, id[i] - 1, 0, mx);
		add_pair(tmp, id[i], 0, mx, 1);
	}
	cout << ans << endl;
}
posted @ 2020-08-04 23:03  kurum!  阅读(140)  评论(0编辑  收藏  举报