今天本蒟蒻终于学会了一个提高-的算法。
传送门:(洛谷)逆序对
题意
对于给定的一段正整数序列,逆序对就是序列中ai>aj且i< j的有序对。知道这概念后,他们就比赛谁先算出给定的一段正整数序列中逆序对的数目。
数据范围
对于50%的数据,n≤2500
对于100%的数据,n≤40000。
代码
#include<cstdio>
#include<iostream>
using namespace std;
typedef long long ll;
const int N=1e5+10;
int a[N],t[N],n;
inline ll merge(int l,int mid,int r)
{
int i=l,j=mid+1,k=0;
ll an=0;
while(i<=mid && j<=r){
if(a[i]>a[j]){
an+=(mid-i+1);//this step
t[k++]=a[j++];
}else{
t[k++]=a[i++];
}
}
while(i<=mid){
t[k++]=a[i++];
}
while(j<=r) t[k++]=a[j++];
for(int g=0;g<k;g++) a[l+g]=t[g];
return an;
}
inline ll query(int l,int r){
ll ans=0;
if(l<r){
int mid=(l+r)>>1;
ans+=query(l,mid);
ans+=query(mid+1,r);
ans+=merge(l,mid,r);
}
return ans;
}
int main(){
scanf("%d",&n);
for(int i=1;i<=n;i++)
scanf("%d",&a[i]);
printf("%lld\n",query(1,n));
return 0;
}
今天(2018.3.30)学会了权值线段树状数组:
#include<bits/stdc++.h>
#define Rg register
using namespace std;
const int N=1e5+10;
typedef long long ll;
int tot[N<<2],mx,tg[N];
int n;ll ans;
struct P{
int v,um;
bool operator< (const P& u)const{
return v<u.v;
}
}a[N];
inline int read()
{
char c=getchar();int x=0;
while(c<'0' || c>'9') {c=getchar();}
while(c>='0' && c<='9') {x=(x<<3)+(x<<1)+(c^48));c=getchar();}
return x;
}
inline int get(int k)
{
int ss=0;
for(;k>0;k-=(k&(-k))){ss+=tot[k];}
return ss;
}
inline void update(int k,int val)
{
for(;k<=mx;k+=(k&(-k))){tot[k]+=val;}
}
int main(){
n=read();
for(Rg int x,i=1;i<=n;i++){
a[i].v=read();
a[i].um=i;
}
sort(a+1,a+n+1);
for(Rg int i=1;i<=n;i++){
if(a[i].v!=a[i-1].v){mx++;}
tg[a[i].um]=mx;
}
mx++;
update(tg[1],1);
for(Rg int i=2;i<=n;i++){
ans+=(i-1-get(tg[i]));
update(tg[i],1);
}
printf("%lld\n",ans);
return 0;
}