【CH4201】樓蘭圖騰
阿新 • • 發佈:2018-12-11
題目大意:給定一個長度為 N 的序列,從序列中任意挑出三個數,求滿足中間的數字值最小(最大)有多少種情況。
題解:建立在值域上的樹狀陣列,從左到右掃描一遍序列,統計出每個點左邊有多少個數大於(小於)該點的值,再從右到左掃描一遍序列,統計出每個點右邊有多少個數大於(小於)自己,最後計算答案貢獻即可。
程式碼如下
#include <bits/stdc++.h> #define cls(a,b) memset(a,b,sizeof(a)) #define lowbit(x) x&-x #define all(x) x.begin(),x.end() using namespace std; const int maxn=2e5+10; inline int read(){ int x=0,f=1;char ch; do{ch=getchar();if(ch=='-')f=-1;}while(!isdigit(ch)); do{x=x*10+ch-'0';ch=getchar();}while(isdigit(ch)); return f*x; } int n,a[maxn],bit[maxn],left1[maxn],left2[maxn],right1[maxn],right2[maxn]; long long ans1,ans2; void read_and_parse(){ n=read(); for(int i=1;i<=n;i++)a[i]=read(); } inline void modify(int x,int val){ for(int i=x;i<=n;i+=lowbit(i))bit[i]+=val; } inline int query(int x){ int ans=0; for(int i=x;i;i-=lowbit(i))ans+=bit[i]; return ans; } void solve(){ for(int i=1;i<=n;i++){ left1[i]=query(a[i]-1); left2[i]=query(n)-query(a[i]); modify(a[i],1); } cls(bit,0); for(int i=n;i>=1;i--){ right1[i]=query(a[i]-1); right2[i]=query(n)-query(a[i]); modify(a[i],1); } for(int i=1;i<=n;i++)ans1+=(long long)left2[i]*right2[i],ans2+=(long long)left1[i]*right1[i]; printf("%lld %lld\n",ans1,ans2); } int main(){ read_and_parse(); solve(); return 0; }