codeforces #261 D题 Pashmak and Parmida's problem(线段树+离散化)

题目地址:http://codeforces.com/contest/459/problem/D

这个题攒了好长时间了,一直也没看。。今天看了下,也不难。当时做的时候明明还有半个多小时可以看这题的,但是。。由于某些人的打扰。。我一直在应付着拒绝。。所以这题当时连看都没来得及看。。以后做CF果断不上QQ了。。。

这题就是求逆序数。需要先预处理每个点的左边与右边与之相同的数的个数。然后用线段树去求逆序数就可以了。因为数的范围是10^9,而数据范围只有10^6,所以要先对其离散化。

代码如下:

#include <iostream>
#include <cstdio>
#include <string>
#include <cstring>
#include <stdlib.h>
#include <math.h>
#include <ctype.h>
#include <queue>
#include <map>
#include <set>
#include <algorithm>

using namespace std;
#define lson l, mid, rt<<1
#define rson mid+1, r, rt<<1|1
#define LL __int64
int dp1[1100000], dp2[1100000], a[1100000], b[1100000], c[1100000], _hash[1100000];
LL sum[5100000];
void PushUp(int rt)
{
    sum[rt]=sum[rt<<1]+sum[rt<<1|1];
}
void update(int p, int l, int r, int rt)
{
    if(l==r)
    {
        sum[rt]++;
        return ;
    }
    int mid=l+r>>1;
    if(p<=mid)
        update(p,lson);
    else
        update(p,rson);
    PushUp(rt);
}
LL query(int ll, int rr, int l, int r, int rt)
{
    if(ll<=l&&rr>=r)
        return sum[rt];
    int mid=l+r>>1;
    LL ans=0;
    if(ll<=mid) ans+=query(ll,rr,lson);
    if(rr>mid) ans+=query(ll,rr,rson);
    return ans;
}
int erfen(int x, int high)
{
    int low=0, mid;
    while(low<=high)
    {
        mid=low+high>>1;
        if(c[mid]>x) high=mid-1;
        else if(c[mid]<x) low=mid+1;
        else return mid;
    }
}
int main()
{
    int n, i, cnt=1, max1=-1;
    scanf("%d",&n);
    LL ans=0;
    for(i=1;i<=n;i++)
    {
        scanf("%d",&a[i]);
        b[i]=a[i];
    }
    sort(b+1,b+1+n);
    c[0]=b[1];
    for(i=2;i<=n;i++)
    {
        if(b[i]!=b[i-1])
        {
            c[cnt++]=b[i];
        }
    }
    for(i=1;i<=n;i++)
    {
        a[i]=erfen(a[i],cnt-1);
    }
    memset(_hash,0,sizeof(_hash));
    for(i=1;i<=n;i++)
    {
        dp1[i]=++_hash[a[i]];
        max1=max(max1,dp1[i]);
    }
    memset(_hash,0,sizeof(_hash));
    for(i=n;i>=1;i--)
    {
        dp2[i]=++_hash[a[i]];
    }
    memset(sum,0,sizeof(sum));
    /*for(i=n;i>=1;i--)
    {
        printf("%d ",dp1[i]);
    }
    printf("\n");
    for(i=n;i>=1;i--)
    {
        printf("%d ",dp2[i]);
    }
    printf("\n");*/
    for(i=n;i>=1;i--)
    {
        ans+=query(0,dp1[i]-1,0,max1,1);
        update(dp2[i],0,max1,1);
        //printf("%I64d\n",ans);
    }
    printf("%I64d\n",ans);
    return 0;
}


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值