逆序对Plus

团队题库链接:https://www.luogu.org/problemnew/show/T24295

逆序对Plus

题目背景

LPA AC了逆序对一题感觉不过瘾, 于是ShadyPi给他出了这样一道题。

题目描述

给定一个序列a[1], a[2], a[3] …, a[n] a[1],a[2],a[3]…,a[n] , 求满足a[i] < a[j] > a[k]a[i]

输入输出格式
输入格式:

第一行一个正整数n, 表示序列长度为n。 第二行n个正整数a[i], 表示序列中每个元素的值。

输出格式:

一个正整数a, 表示答案为a。

输入输出样例
输入样例#1:

5
1 2 3 4 1

输出样例#1:

6

说明

对于20%的数据, n<=10000n<=10000

对于50%的数据, n <= 100000n<=100000 ;

对于100%的数据, n <= 400000n<=400000 , 0 < a[i] <= 21474836470

题解

正解是建两次值域线段树,但是博主不晓得什么值域线段树,就用普通线段树艹过去了。。。

下面以统计 a[i]<a[j],i<j a [ i ] < a [ j ] , i < j 为例讲解:

我们只需要按权值大小排一次序,从小到大插入每个点,线段树维护区间内已经插入的点数,每次先查找该点左边插入点的数目,因为是从小到大插的所以此时左边插入的点数就等于 a[i]<a[j],i<j a [ i ] < a [ j ] , i < j 的数目。

值得注意的是,排序的时候我们要把权值相同的节点中位置靠后的放在前面,把位置靠后的先插进树里,这样才不会把权值相同的在自己前面的点统计进去。

另外一半类似,大家结合左半边和代码理解吧。

代码
#include<bits/stdc++.h>
using namespace std;
const int M=1e6+5;
const int mod=666233;
struct sd{
    int val,pos;
};
long long tree[M<<1],ans[M],cot[M],tong[M],n;
sd x[M];
bool cmp1(sd a,sd b){return a.val==b.val?a.pos>b.pos:a.val<b.val;}
bool cmp2(sd a,sd b){return a.val==b.val?a.pos<b.pos:a.val<b.val;}
void up(int v)
{tree[v]=tree[v<<1]+tree[v<<1|1];}
void in()
{
    scanf("%d",&n);
    for(int i=1;i<=n;++i)
    scanf("%d",&x[i].val),x[i].pos=i;
}
void ins(int v,int pos,int le,int ri)
{
    if(le==ri&&le==pos)
    {
        tree[v]=1;
        return;
    }
    int mid=(le+ri)>>1;
    if(pos<=mid)ins(v<<1,pos,le,mid);
    else ins(v<<1|1,pos,mid+1,ri);
    up(v);
}
long long ques(int v,int le,int ri,int ll,int rr)
{
    if(ll<=le&&ri<=rr)return tree[v];
    int mid=(le+ri)>>1,ans=0;
    if(ll<=mid)ans=ques(v<<1,le,mid,ll,rr);
    if(rr>mid)ans+=ques(v<<1|1,mid+1,ri,ll,rr);
    return ans;
}
void ac()
{
    sort(x+1,x+1+n,cmp1);
    for(int i=1;i<=n;++i)
    {
        ans[x[i].pos]=ques(1,1,n,1,x[i].pos);
        ans[x[i].pos]%=mod;
        ins(1,x[i].pos,1,n);
    }
    sort(x+1,x+1+n,cmp2);
    memset(tree,0,sizeof(tree));
    for(int i=1;i<=n;++i)
    {
        ans[x[i].pos]*=ques(1,1,n,x[i].pos,n);
        ans[x[i].pos]%=mod;
        ins(1,x[i].pos,1,n);
    }
    long long hh=0;
    for(int i=1;i<=n;++i)
    hh+=ans[i],hh%=mod;
    printf("%lld",hh);
}
int main()
{
    in();ac();
    return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

ShadyPi

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

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

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

打赏作者

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

抵扣说明:

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

余额充值