luogu P1637 三元上升子序列
阿新 • • 發佈:2021-08-20
我們可以列舉中間數,然後一分為二計算前面比本元素小的*後面比本元素大的,累加起來就是答案。
首先需要離散化,預處理兩個陣列l[i],r[i]表示左邊比i小和左邊比i大的。
開個權值樹狀陣列,l[i]很好計算 ,r[i]需要變化一下,倒序計算r[i],那麼當前計算出的sum表示的i+1n中小於等於a[i]的,用n-i減去sum就是i+1n大於a[i]的數量
程式碼
#include<bits/stdc++.h> #define rep(i,j,k) for(register int i(j);i<=k;++i) #define drp(i,j,k) for(register int i(j);i>=k;--i) using namespace std; typedef long long lxl; template<typename T> inline T max(T &a, T &b) { return a > b ? a : b; } template<typename T> inline T min(T &a, T &b) { return a < b ? a : b; } inline char gt() { static char buf[1 << 21], *p1 = buf, *p2 = buf; return p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, 1 << 21, stdin), p1 == p2) ? EOF : *p1++; } template <typename T> inline void read(T &x) { register char ch = gt(); x = 0; int w(0); while(!(ch >= '0' && ch <= '9'))w |= ch == '-', ch = gt(); while(ch >= '0' && ch <= '9')x = x * 10 + (ch & 15), ch = gt(); w ? x = ~(x - 1) : x; } template <typename T> inline void out(T x) { if(x < 0) x = -x, putchar('-'); char ch[20]; int num(0); while(x || !num) ch[++num] = x % 10 + '0', x /= 10; while(num) putchar(ch[num--]); putchar('\n'); } int n; const int N=3e5+79; struct BIT{ int c[N]; inline int lowbit(int x){ return x&(-x); } inline void add(int x,int val){ for(;x<=n;x+=lowbit(x)) c[x]+=val; } inline lxl ask(int x){ lxl ans(0); for(;x;x-=lowbit(x)) ans+=c[x]; return ans; } }B,BB; lxl a[N], k[N]; int l[N],r[N];//左邊小於,右邊大於 vector<lxl>b; inline int getid(int x){ return lower_bound(b.begin(),b.end(),x)-b.begin()+1; } int main() { read(n); rep(i, 1, n) { read(a[i]); b.push_back(a[i]); } sort(b.begin(), b.end()); b.erase(unique(b.begin(), b.end()), b.end()); rep(i, 1, n) { k[i] = getid(a[i]); } rep(i,1,n){ l[i]=B.ask(k[i]-1); B.add(k[i],1); }//查詢前面的比 drp(i,n,1){ r[i]=n-i-BB.ask(k[i]); BB.add(k[i],1); }//後i~n中小於k[i] lxl ans(0); rep(i,2,n-1 ) ans=ans+l[i]*r[i]; out(ans); return 0; }
本文來自部落格園,作者:{2519},轉載請註明原文連結:https://www.cnblogs.com/QQ2519/p/15168041.html