cf 459D Pashmak and Parmida's problem 树状数组


给你n个数(1<=n<=1e6),定义 f (l , r , x)为区间 [ l  ,  r   ]   内与 x

相等的数的个数。问你有多少对  i  ,  j  (i  <   j)使得  f (1 , i , a[  i  ]) >    f (j , n , a[  j  ])。

问1到i区间有多少数和a[ i  ]相等显然可以预处理出来,得  pre[ i ]  ==    f (1 , i , a[  i  ])

 同理得suf[ j  ]   ==   f (j , n , a[  j  ])。在满足偏序关系  i  <   j  时又要满足偏序关系

f (1 , i , a[  i  ]) >    f (j , n , a[  j  ]) (pre[ i ]  > suf [ j  ] ),可以用树状数组高效实现。

树状数组的更新会自动满足 i  <   j的条件, 现枚举 i ,树状数组里存的是suf [ j  ],

每次查询比pre[ i ] 小的suf [ j  ]的个数,加到ans里就好了。(这道题目也可以用线段树做)。

注意树状数组里存的值可能会超过 int 。


#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<vector>
#include<cmath>
#include<string>
#include<algorithm>
#include<set>
#include<map>
#include<cstring>
#include<queue>
#include<stack>
#include<list>

using namespace std;

typedef long long ll;
const int MAXN=1000000+5;
const ll INF=1e9;
const ll mod=1e9+7;

int a[MAXN];
int suf[MAXN],pre[MAXN];
ll bit[MAXN];
int n;

ll sum(int x){
    ll ans=0;
    while(x>0){
        ans+=bit[ x ];
        x-=x&-x;
    }
    return ans;
}

void add(int i,ll x){
    while( i<=n ){
        bit[i]+=x;
        i+=i&-i;
    }
}


int main()
{
	//freopen("A-large.in","r",stdin);
    	//freopen("A-large.out","w",stdout);

    scanf("%d",&n);
    for(int i=1;i<=n;i++){
        scanf("%d",&a[i]);
    }
    map<int,int > mp;
    for(int i=1;i<=n;i++){
        mp[ a[i] ]++;
        pre[i]=mp[ a[i] ];
    }
    mp.clear();
    for(int i=n;i>=1;i--){
        mp[a[i]]++;
        suf[i]=mp[ a[i] ];
    }
    memset(bit,0,sizeof(bit));
    ll ans=0;
    for(int i=n;i>=1;i--){
        ans+=sum( pre[i]-1 );
        add( suf[i],1 );
    }
    printf("%I64d\n",ans);

	return 0;
}



  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值