Luogu P1637 三元上升子序列

Posted zhylj

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Luogu P1637 三元上升子序列相关的知识,希望对你有一定的参考价值。

对于每个数$a_i$,易得它对答案的贡献为 它左边比它小的数的个数$ imes$它右边比它大的数的个数。

可以离散化后再处理也可以使用动态开点的线段树。

我使用了动态开点的线段树,只有需要用到这个节点的时候才新建这个节点,这里我是在进行修改的时候新建的。

时间复杂度$O(nlog (max m MAX\_INT))$,空间复杂度$O(nlog (max m MAX\_INT))$(常数真的很大)

以下是代码,不清楚的地方已标出。

 1 #include <bits/stdc++.h>
 2 
 3 using namespace std;
 4 
 5 typedef long long ll;
 6 
 7 const ll MAXN = 3e4 + 5, inf = 0x7fffffffLL + 5LL;
 8 
 9 ll ans = 0, kans[MAXN], a[MAXN], n;
10 
11 struct node{
12 
13     ll data;
14     node *lc, *rc;
15 
16     void pushup() {
17         data = 0;
18         if(lc) data += lc->data;
19         if(rc) data += rc->data;
20     }
21 
22     node() {
23         data = 0;
24         lc = rc = NULL;
25     }
26 
27 } *st1 = new node, *st2 = new node;  //建立两棵线段树
28 
29 ll query(node *&cur, ll l, ll r, ll ql, ll qr) {
30     if(!cur) return 0;  //防止访问无效内存
31     if(ql <= l && r <= qr) {
32         return cur->data;
33     }
34     ll mid = (l + r) >> 1, ans = 0;
35     if(ql <= mid) ans += query(cur->lc, l, mid, ql, qr);
36     if(qr > mid) ans += query(cur->rc, mid + 1, r, ql, qr);
37     return ans;
38 }
39 
40 void modify(node *&cur, ll l, ll r, ll q, ll k) {
41     if(!cur) cur = new node;  //新建节点
42     if(l == r) cur->data += k;
43     else {
44         ll mid = (l + r) >> 1;
45         if(q <= mid) modify(cur->lc, l, mid, q, k);
46         else modify(cur->rc, mid + 1, r, q, k);
47         cur->pushup();
48     }
49 }
50 
51 void solve() {
52     for(ll i = 0; i < n; i++) {
53         kans[i] = query(st1, 1, inf, 1, a[i] - 1);  //得到它左边比它小的数的个数
54         modify(st1, 1, inf, a[i], 1);
55     }
56     for(ll i = n - 1; i >= 0; i--) {
57         kans[i] *= query(st2, 1, inf, a[i] + 1, inf);  //得到右边比它大的数的个数
58         modify(st2, 1, inf, a[i], 1);
59     }
60 }
61 
62 int main () {
63     cin >> n;
64     for(ll i = 0; i < n; i++) cin >> a[i], a[i]+=2;  //为了防止访问到0,这里直接加上2,是不改变结果的
65     solve();
66     for(ll i = 0; i < n; i++) ans += kans[i];
67     cout << ans << endl;
68     return 0;
69 }

 











以上是关于Luogu P1637 三元上升子序列的主要内容,如果未能解决你的问题,请参考以下文章

洛谷P1637 三元上升子序列

P1637 三元上升子序列

P1637 三元上升子序列

P1637 三元上升子序列

洛谷 P1637 三元上升子序列Treap

『Luogu 1637』三元上升子序列 (树状数组)