//主要考察求解逆序数,两列元素互联求交点个数,先对一列元素排序,再求出另一列的逆序数,依照题意,相同情况下不算排序的时候应该注意,结果应该用long long保存。
看了 下分别用可以用树状数组和归并排序求逆序数。
用树状数组求,先把第二列y按照从大到小排序,这样再插入的时候先从大的x开始插入update,后求比x小元素的和getSum(x-1)。
#include <cstdio>
#include <cstring>
#include <algorithm>
#define Max 1010
using namespace std;
typedef long long ll;
struct Node{
int x,y;
bool operator < (const Node &b) const
{
if(y==b.y) return x>b.x;
return y>b.y;
}
}a[Max*Max];
ll c[Max];
int lowbit(int x)
{
return x&(-x);
}
void update(int x)
{
while(x<Max)
{
c[x]++;
x+=lowbit(x);
}
}
ll getSum(int x)
{
ll sum=0;
while(x>0)
{
sum+= c[x];
x=x-lowbit(x);
}
return sum;
}
int main(int argc, char const *argv[])
{
int t;
int n,m,k;
ll sum;
scanf("%d",&t);
for(int cas=1; cas<=t; cas++)
{
sum=0;
memset(c,0,sizeof(c));
scanf("%d %d %d",&n,&m,&k);
for(int i=1; i<=k ; i++)
{
scanf("%d %d",&a[i].x,&a[i].y);
}
sort(a+1,a+1+k);
for(int j=1; j<=k; j++)
{
sum+=getSum(a[j].x-1);
update(a[j].x);
}
printf("Test case %d: %lld\n",cas,sum);
}
return 0;
}
用归并排序做法,我是按x从小到大排序,接着求y的逆序数,在合并的时候若后部分比前部分小,则证明当前元素逆序数为(n1-i)个
#include <cstdio>
#include <stdlib.h>
#include <algorithm>
#define Max 1010
using namespace std;
struct Node{
int x, y;
}a[Max*Max];
long long ans=0;
bool cmp(Node a,Node b)
{
if(a.x==b.x) return a.y<b.y;
return a.x<b.x;
}
void merge(int l,int m,int r)
{
int i,j;
int n1=m-l+1;
int n2=r-m;
int f[n1+1];
int b[n2+1];
for(i=0; i<n1; i++)
{
f[i]=a[l+i].y;
}
for(i=0; i<n2; i++)
{
b[i]=a[m+i+1].y;
}
i=j=0;
f[n1]=Max;
b[n2]=Max;
for(int k=l; k<=r; k++)
{
if(f[i]<=b[j])
{
a[k].y=f[i++];
}else
{
ans+=(long long )(n1-i);
a[k].y=b[j++];
}
}
}
void mergesort(int l,int r)
{
if(l<r)
{
int m=(l+r)/2;
mergesort(l,m);
mergesort(m+1,r);
merge(l,m,r);
}
}
int main(int argc, char const *argv[])
{
int t;
int n,m,k;
scanf("%d",&t);
for(int cas=1; cas<=t; cas++)
{
scanf("%d %d %d",&n,&m,&k);
for(int i=0; i<k; i++)
{
scanf("%d %d",&a[i].x,&a[i].y);
}
sort(a,a+k,cmp);
ans=0;
mergesort(0,k-1);
printf("Test case %d: %lld\n",cas,ans);
}
return 0;
}