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 三元上升子序列的主要内容,如果未能解决你的问题,请参考以下文章