最近刚开始学线性代数,一开始看到这道题想到求逆序数。求法的话一开始想的是建立线段树,储存最大元,然后每个元都跟后面的线段的最小元比较,如果小于就加上区间长度。但是这样建立线段树效率并不高,因为后面的元随机嘛,若是123123这样的序列,并没有优化太多,不出意外的超时了。
然后查了一下资料,这道题要用到离散化,重新建立一组映射
推荐一篇博客写的很好:https://blog.csdn.net/wyg1997/article/details/52047491
AC代码:
#include <stdlib.h>
#include <cstdio>
#include <iostream>
#include <queue>
#include <stack>
#include <string.h>
#include <math.h>
#include <algorithm>
#define mem(t, v) memset ((t) , v, sizeof(t))
#define INF 0x3f3f3f3f
#define eps 1e-8
typedef long long ll;
using namespace std;
const int MAX=500050;
int m,n;
char cmd[10];
struct node{
int sum,l,r;
}tree[MAX*4];
struct s{
int val;
int num;
}in[MAX];
bool cmp(s a,s b){
return a.val<b.val;
}
void Build(int i,int l, int r){
tree[i].l=l,tree[i].r=r;
tree[i].sum=tree[i].r-tree[i].l+1;
if(l==r) return ;
int mid=(l+r)>>1;
Build(i<<1,l,mid);
Build(i<<1|1,mid+1,r);
}
void Update(int i,int x,int y){
if(tree[i].l==tree[i].r){
tree[i].sum+=y;
return ;
}
if(tree[i<<1].r>=x)Update(i<<1,x,y);
if(tree[i<<1|1].l<=x)Update(i<<1|1,x,y);
tree[i].sum=tree[i<<1].sum+tree[i<<1|1].sum;
}
ll Search(int i,int l,int r){
if(tree[i].l>=l&&tree[i].r<=r)
return tree[i].sum;
if(tree[i].l>r||tree[i].r<l)
return 0;
ll s=0;
if(tree[i<<1].r>=l)s+=Search(i<<1,l,r);
if(tree[i<<1|1].l<=r)s+=Search(i<<1|1,l,r);
return s;
}
int main(){
while(scanf("%d",&n),n){
for(int i=1;i<=n;i++){
scanf("%d",&in[i].val);
in[i].num=i;
}
sort(in+1,in+n+1,cmp);
// for(int i=1;i<=n;i++)
// printf("%d %d*",in[i].num,in[i].val);
// printf("\n");
Build(1,1,n);
ll ans=0;
for(int i=1;i<=n;i++){
ans+=Search(1,1,in[i].num-1);
//printf("%d\n",ans);
Update(1,in[i].num,-1);
}
printf("%lld\n",ans);
}
}