【转自BLOG】点击打开链接
【1 POJ.2299】
离散化是一种常用的技巧,有时数据范围太大,可以用来放缩到我们能处理的范围 因为其中需排序的数的范围0---
999999999;显然数组不肯能这么大;而N的最大范围是500000;故给出的数一定可以与1.。。。N建立一个一一映射;
这里用一个结构体
struct Node
{
int v,order;
}a[510000];
和一个数组aa[510000];
其中v就是原输入的值,order是下标;然后对结构体按v从小到大排序;此时,v和结构体的下标就是一个一一对应关系,而且
满足原来的大小关系;
for(i=1;i<=N;i++)
aa[a[i].order]=i;
然后a数组就存储了原来所有的大小信息;比如 9 1 0 5 4 ------- 离散后aa数组就是 5 2 1 4 3;具体的过程可以自己
用笔写写就好了。
离散之后,怎么使用离散后的结果数组来进行树状数组操作,计算出逆序数?
如果数据不是很大,可以一个个插入到树状数组中,每插入一个数,统计比他小的数的个数,对应的逆序为 i- getsum(aa
[i]),其中i为当前已经插入的数的个数,getsum(aa[i])为比aa[i]小的数的个数,i- sum(aa[i]) 即比aa[i]大的个数,
即逆序的个数但如果数据比较大,就必须采用离散化方法。
【AC code】
//POJ.2299
//Ultra-QuickSort
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const int maxn=500010;
#define ll long long
struct node{
int v,order;
friend bool operator<(const node &p,const node &q)
{
return p.v<q.v;
}
}a[maxn];//输入部分
int aa[maxn];//离散化后的数组
int c[maxn];//树状数组
int n;
void init()
{
memset(c,0,sizeof(c));
}
int getsum(int i)
{
int s=0;
while(i>0)
{
s+=c[i];
i-=i&-i;
}
return s;
}
void add(int i,int x)
{
while(i<=n)
{
c[i]+=x;
i+=i&-i;
}
}
int main()
{
while(scanf("%d",&n)!=EOF)
{
if(n==0) break;
for(int i=1; i<=n; i++)
{
scanf("%d",&a[i].v);
a[i].order=i;
}
sort(a+1,a+n+1);
for(int i=1; i<=n; i++)
{
aa[a[i].order]=i;
}
init();
ll ans=0;
for(int i=1; i<=n; i++)
{
add(aa[i],1);
ans+=i-getsum(aa[i]);
}
printf("%lld\n",ans);
}
}
【2 HDU.2492】
【题意】有两个人可以参加比赛,但是他们必须选一个裁判,并且这个裁判的能力值不能比这个人高,也不能比这个人低,求满足的方案数!对于每个人,只需要统计左边比他高,右边比他低的人数或者,统计左边比他低,右边比他高的人数,这两种选择的方案数之和就是整个的方案数。
【AC code】
//HDU.2492
#include<cstdio>
#include<cstring>
#include<cmath>
#include<cctype>
#include<iostream>
using namespace std;
#define ll long long
const int maxn=100005;
int a[maxn],b[maxn],c[maxn],d[maxn],e[maxn],f[maxn];
int getInt(int &x)
{
return scanf("%d",&x);
}
int n;
int low_bit(int x)
{
return x&(-x);
}
void update(int x,int v)
{
while(x<=maxn)
{
a[x]+=v;
x+=low_bit(x);
}
}
int get_sum(int x)
{
int sum=0;
while(x>0)
{
sum+=a[x];
x-=low_bit(x);
}
return sum;
}
int main()
{
int tt;ll ans;
getInt(tt);
while(tt--)
{
getInt(n);
memset(a,0,sizeof(a));
ans=0;
for(int i=1;i<=n;i++)
{
getInt(b[i]);
}
for(int i=1;i<=n;i++)
{
update(b[i],1);
c[i]=get_sum(maxn)-get_sum(b[i]); //左边有多少个数比自己大
d[i]=get_sum(b[i]-1); //左边有多少个数比自己小
}
memset(a,0,sizeof(a));
for(int i=n;i>=1;i--)
{
update(b[i],1);
e[i]=get_sum(maxn)-get_sum(b[i]); //右边有多少个数比自己大
f[i]=get_sum(b[i]-1); //右边有多少个数比自己小
}
for(int i=1;i<=n;i++)
{
ans+=c[i]*f[i]+d[i]*e[i];
}
printf("%lld\n",ans);
}
return 0;
}