题目链接:点击进入
题目
思路1(树状数组+离散化)
求逆序对,这个题给的范围为 1e9 ,正常的话是将数作为下标并修改对应值,但是这里要是将数当作下标肯定不行,因为开不了 1e9 那么大的数组,因此我们对其离散化一下 ( 也就是排序,按照大小赋予编号 ),这样我们用编号进行树状数组的修改,数组最大只需要开1e6 即可。( 仔细想一下,离散化其实就是将原来中间没有赋值的那些位置除去了,留下只会被用到的位置,虽然给这些位置重新编号了,但是实际上相对位置是没变的 )
离散结束就是正常的操作了,例如此题。
代码1
//#pragma GCC optimize(3)//O3
//#pragma GCC optimize(2)//O2
#include<iostream>
#include<string>
#include<map>
#include<set>
//#include<unordered_map>
#include<queue>
#include<cstdio>
#include<vector>
#include<cstring>
#include<stack>
#include<algorithm>
#include<iomanip>
#include<cmath>
#include<fstream>
#define X first
#define Y second
#define best 131
#define INF 0x3f3f3f3f3f3f3f3f
#define pii pair<int,int>
#define lowbit(x) x & -x
#define inf 0x3f3f3f3f
#define int long long
//#define double long double
//#define rep(i,x,y) for(register int i = x; i <= y;++i)
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const double pai=acos(-1.0);
const int maxn=1e6+10;
const int mod=1e9+7;
const double eps=1e-9;
const int N=5e3+10;
/*--------------------------------------------*/
inline int read()
{
int k = 0, f = 1 ;
char c = getchar() ;
while(!isdigit(c)){if(c == '-') f = -1 ;c = getchar() ;}
while(isdigit(c)) k = (k << 1) + (k << 3) + c - 48 ,c = getchar() ;
return k * f ;
}
/*--------------------------------------------*/
int n,c[maxn],mp[maxn],ans;
struct node
{
int pos;
int num;
bool operator < (const node&t)const
{
return num<t.num;
}
}p[maxn];
void add(int x,int d)
{
for(int i=x;i<=n;i+=lowbit(i)) c[i]+=d;
}
int getsum(int x)
{
int sum=0;
for(int i=x;i>=1;i-=lowbit(i)) sum+=c[i];
return sum;
}
signed main()
{
// ios::sync_with_stdio(false);
// cin.tie(0);cout.tie(0);
cin>>n;
for(int i=1;i<=n;i++)
{
cin>>p[i].num;
p[i].pos=i;
}
sort(p+1,p+n+1);
int cnt=1;
mp[p[1].pos]=cnt;
for(int i=2;i<=n;i++)
{
if(p[i].num==p[i-1].num)
mp[p[i].pos]=cnt;
else
mp[p[i].pos]=++cnt;
}
for(int i=1;i<=n;i++)
{
ans=ans+(getsum(n)-getsum(mp[i]));
add(mp[i],1);
}
cout<<ans<<endl;
return 0;
}
思路2(线段树+离散化)
一个意思,线段树开不了 4e9 的空间,因此离散化一下 ( 也就是排序,按照大小赋予编号 ),这样我们只需要对离散后的编号操作即可,因为相对大小关系没变化,因此求得的数量是一样的。
代码2
//#pragma GCC optimize(3)//O3
//#pragma GCC optimize(2)//O2
#include<iostream>
#include<string>
#include<map>
#include<set>
//#include<unordered_map>
#include<queue>
#include<cstdio>
#include<vector>
#include<cstring>
#include<stack>
#include<algorithm>
#include<iomanip>
#include<cmath>
#include<fstream>
#define X first
#define Y second
#define best 131
#define INF 0x3f3f3f3f3f3f3f3f
#define pii pair<int,int>
#define lowbit(x) x & -x
#define inf 0x3f3f3f3f
#define int long long
//#define double long double
//#define rep(i,x,y) for(register int i = x; i <= y;++i)
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const double pai=acos(-1.0);
const int maxn=1e6+10;
const int mod=1e9+7;
const double eps=1e-9;
const int N=5e3+10;
/*--------------------------------------------*/
inline int read()
{
int k = 0, f = 1 ;
char c = getchar() ;
while(!isdigit(c)){if(c == '-') f = -1 ;c = getchar() ;}
while(isdigit(c)) k = (k << 1) + (k << 3) + c - 48 ,c = getchar() ;
return k * f ;
}
/*--------------------------------------------*/
int n,mp[maxn],ans;
struct node
{
int pos;
int num;
bool operator < (const node&t)const
{
return num<t.num;
}
}p[maxn];
struct Node
{
int l;
int r;
int sum;
}t[maxn<<2];
void pushup(int p)
{
t[p].sum=t[p<<1].sum+t[p<<1|1].sum;
}
void build(int p,int l,int r)
{
t[p].l=l,t[p].r=r,t[p].sum=0;
if(l==r) return ;
int mid=l+r>>1;
build(p<<1,l,mid);
build(p<<1|1,mid+1,r);
pushup(p);
}
void change(int p,int x,int d)
{
if(t[p].l==t[p].r)
{
t[p].sum+=d;
return ;
}
int mid=t[p].l+t[p].r>>1;
if(x<=mid) change(p<<1,x,d);
else change(p<<1|1,x,d);
pushup(p);
}
int ask(int p,int l,int r)
{
if(l<=t[p].l&&t[p].r<=r)
return t[p].sum;
int mid=t[p].l+t[p].r>>1,ans=0;
if(l<=mid) ans+=ask(p<<1,l,r);
if(r>mid) ans+=ask(p<<1|1,l,r);
return ans;
}
signed main()
{
// ios::sync_with_stdio(false);
// cin.tie(0);cout.tie(0);
cin>>n;
for(int i=1;i<=n;i++)
{
cin>>p[i].num;
p[i].pos=i;
}
sort(p+1,p+n+1);
int cnt=1;
mp[p[1].pos]=cnt;
for(int i=2;i<=n;i++)
{
if(p[i].num==p[i-1].num)
mp[p[i].pos]=cnt;
else
mp[p[i].pos]=++cnt;
}
build(1,1,cnt);
for(int i=1;i<=n;i++)
{
change(1,mp[i],1);
ans=ans+(i-ask(1,1,mp[i]));
}
cout<<ans<<endl;
return 0;
}
思路3(线段树+动态开点)
线段树开不了 4e9 的空间,那我们可以考虑动态开点,也就是说我们没有用到的那些节点,我们不去赋予它空间,只给那些有用的点空间即可。而对于这种用到才开点的方式也就意味着不能通过 p<<1 , p<<1|1 的方式,访问子节点了,编号变成乱序的了。也就是t [ p ] . l 、 t [ p ]. r 存的是左右孩子的下标,但是编号是乱序的,是我们需要使用时现加上去的。
( 注:更新函数里下标 p 前面的 & 不可省略 )
这里用了动态开点,就可以不用离散化,直接1~1e9操作即可。
代码3
//#pragma GCC optimize(3)//O3
//#pragma GCC optimize(2)//O2
#include<iostream>
#include<string>
#include<map>
#include<set>
//#include<unordered_map>
#include<queue>
#include<cstdio>
#include<vector>
#include<cstring>
#include<stack>
#include<algorithm>
#include<iomanip>
#include<cmath>
#include<fstream>
#define X first
#define Y second
#define best 131
#define INF 0x3f3f3f3f3f3f3f3f
#define pii pair<int,int>
#define lowbit(x) x & -x
#define inf 0x3f3f3f3f
//#define int long long
//#define double long double
//#define rep(i,x,y) for(register int i = x; i <= y;++i)
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const double pai=acos(-1.0);
const int maxn=1e7+10;
const int mod=1e9+7;
const double eps=1e-9;
const int N=5e3+10;
/*--------------------------------------------*/
inline int read()
{
int k = 0, f = 1 ;
char c = getchar() ;
while(!isdigit(c)){if(c == '-') f = -1 ;c = getchar() ;}
while(isdigit(c)) k = (k << 1) + (k << 3) + c - 48 ,c = getchar() ;
return k * f ;
}
/*--------------------------------------------*/
int n,a[maxn],root,cnt,limit;
ll ans;
struct node
{
int l;
int r;
int sum;
}t[maxn];
void pushup(int p)
{
t[p].sum=t[t[p].l].sum+t[t[p].r].sum;
}
void change(int &p,int l,int r,int x,int d)
{
if(!p) p=++cnt;
if(l==r)
{
t[p].sum+=d;
return ;
}
int mid=l+r>>1;
if(x<=mid) change(t[p].l,l,mid,x,d);
else change(t[p].r,mid+1,r,x,d);
pushup(p);
}
int ask(int p,int l,int r,int x,int y)
{
if(!p) return 0;
if(x<=l&&r<=y)
return t[p].sum;
int mid=l+r>>1,ans=0;
if(x<=mid) ans+=ask(t[p].l,l,mid,x,y);
if(y>mid) ans+=ask(t[p].r,mid+1,r,x,y);
return ans;
}
int main()
{
// ios::sync_with_stdio(false);
// cin.tie(0);cout.tie(0);
limit=1e9;
cin>>n;
for(int i=1;i<=n;i++) cin>>a[i];
for(int i=1;i<=n;i++)
{
change(root,1,limit,a[i],1);
ans=ans+(i-ask(root,1,limit,1,a[i]));
}
cout<<ans<<endl;
return 0;
}