【CH4201】楼兰图腾

题目大意:给定一个长度为 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;
} 

猜你喜欢

转载自www.cnblogs.com/wzj-xhjbk/p/10101372.html