楼兰图腾(树状数组)

楼兰图腾

题目链接

在完成了分配任务之后,西部 314 来到了楼兰古城的西部。

相传很久以前这片土地上(比楼兰古城还早)生活着两个部落,一个部落崇拜尖刀(V),一个部落崇拜铁锹(),他们分别用 V 的形状来代表各自部落的图腾。

西部 314 在楼兰古城的下面发现了一幅巨大的壁画,壁画上被标记出了 n 个点,经测量发现这 n 个点的水平位置和竖直位置是两两不同的。

西部 314 认为这幅壁画所包含的信息与这 n 个点的相对位置有关,因此不妨设坐标分别为 ( 1 , y 1 ) , ( 2 , y 2 ) , … , ( n , y n ) (1,y_1),(2,y_2),…,(n,y_n) (1,y1),(2,y2),,(n,yn),其中 y 1 ∼ y n y_1∼y_n y1yn 是 1 到 n 的一个排列。

西部 314 打算研究这幅壁画中包含着多少个图腾。

如果三个点 ( i , y i ) , ( j , y j ) , ( k , y k ) (i,y_i),(j,y_j),(k,y_k) (i,yi),(j,yj),(k,yk) 满足 1 ≤ i < j < k ≤ n 1≤i<j<k≤n 1i<j<kn y i > y j , y j < y k y_i>y_j,y_j<y_k yi>yj,yj<yk,则称这三个点构成 V 图腾;

如果三个点 ( i , y i ) , ( j , y j ) , ( k , y k ) (i,y_i),(j,y_j),(k,y_k) (i,yi),(j,yj),(k,yk) 满足 1 ≤ i < j < k ≤ n 1≤i<j<k≤n 1i<j<kn y i < y j , y j > y k yi<y_j,y_j>y_k yi<yj,yj>yk,则称这三个点构成 图腾;

西部 314 想知道,这 n 个点中两个部落图腾的数目。

因此,你需要编写一个程序来求出 V 的个数和 的个数。

输入格式

第一行一个数 n。

第二行是 n 个数,分别代表 y 1 , y 2 , … , y n y_1,y_2,…,y_n y1y2,,yn

输出格式

两个数,中间用空格隔开,依次为 V 的个数和 的个数。

数据范围

对于所有数据,n≤200000,且输出答案不会超过 int64。
y 1 ∼ y n y_1∼y_n y1yn 是 1 到 n 的一个排列。

输入样例:

5
1 5 3 2 4

输出样例:

3 4

难度:简单
时/空限制:1s / 64MB
总通过数:3601
总尝试数:6049
来源:《算法竞赛进阶指南》

思路

对于数列中的每一个数字,计算它前面比它小的数字的数量 p r e v m n prevmn prevmn,后面比它小的数字的数量 p o s t m n postmn postmn,前面比它大的数字的数量 p r e v m x prevmx prevmx,后面比它大的数字的数量 p o s t m x postmx postmx,即可求出最终结果。
由于题目描述:y1∼yn 是 1 到 n 的一个排列,所以只需要通过树状数组计算出 p r e v m n prevmn prevmn,其余几个量都可以推导出来。

#include<cstdio>
#include<algorithm>
#define int long long
using namespace std;
const int maxn=2e5+10;
int a[maxn],c[maxn],n,ans1,ans2;

int ask(int x){
    int ret=0;
    for(;x;x-=(x&-x))   ret+=c[x];
    return ret;
}

void add(int x){
    for(;x<maxn;x+=(x&-x))  c[x]++;
}

signed main(){
    scanf("%lld",&n);
    for(int i=1;i<=n;i++)   scanf("%lld",&a[i]);
    for(int i=1;i<=n;i++){
        int prevmn=ask(a[i]-1),postmn=a[i]-1-prevmn;
        int prevmx=i-prevmn-1,postmx=n-a[i]-prevmx;
        add(a[i]);
        ans1+=prevmx*postmx,ans2+=prevmn*postmn;
    }
    printf("%lld %lld",ans1,ans2);
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

m0_51864047

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值