zoukankan      html  css  js  c++  java
  • [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 '
    '
    #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;
    }
    
  • 相关阅读:
    Effective Java 第三版——72. 赞成使用标准异常
    Effective Java 第三版——71. 避免不必要地使用检查异常
    Effective Java 第三版——70. 对可恢复条件使用检查异常,对编程错误使用运行时异常
    Effective Java 第三版——69. 仅在发生异常的条件下使用异常
    Effective Java 第三版——68. 遵守普遍接受的命名约定
    Effective Java 第三版——67. 明智谨慎地进行优化
    Effective Java 第三版——66. 明智谨慎地使用本地方法
    Effective Java 第三版——65. 接口优于反射
    Effective Java 第三版——64. 通过对象的接口引用对象
    Effective Java 第三版——63. 注意字符串连接的性能
  • 原文地址:https://www.cnblogs.com/hfcdyp/p/13436907.html
Copyright © 2011-2022 走看看