树状数组求逆序对 c语言,求逆序对的两种方法(树状数组/归并排序)

这篇博客介绍了如何使用树状数组和归并排序来解决逆序对问题。树状数组通过离散化和线性更新、查询,高效计算逆序对数量;归并排序则在排序过程中统计逆序对,通过维护一个辅助数组记录逆序次数。两种方法都展示了在大数据量下解决问题的高效策略。
摘要由CSDN通过智能技术生成

例题:poj2299

看代码就好了

树状数组:

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#define mem(a,b) memset(a,b,sizeof(a))

#define MOD 100000007

#define ll long long

#define INF 0x3f3f3f3f

const double pi = acos(-1.0);

const int Maxn=50000;

using namespace std;

inline int scan()

{

int x=0,c=1;

char ch=' ';

while((ch>'9'||ch

while(ch=='-')c*=-1,ch=getchar();

while(ch<='9'&&ch>='0')x=x*10+ch-'0',ch=getchar();

return x*c;

}

/**********************************树状数组+离散化*******************************/

ll c[500010];

ll n;

ll lowbit(ll x){

return x&-x;

}

void add(ll i){

while(i<=n){

c[i]++;

i+=lowbit(i);

}

}

ll getnum(ll i){

ll num=0;

while(i>0){

num+=c[i];

i-=lowbit(i);

}

return num;

}

struct node{

ll v,i;

friend bool operator < (node a,node b){

return a.v

}

}nd[500010];

int main(){

while(scanf("%lld",&n)&&n){

mem(nd,0);

mem(c,0);

mapmp;

int v;

ll k=0;

for(int i=1;i<=n;i++){

scanf("%d",&v);

if(!mp[v]){//要去重!!!

nd[++k].v=v;

nd[k].i=k;

mp[v]=1;

}

}

n=k;

sort(nd+1,nd+n+1);

ll ans=0;

for(int i=1;i<=n;i++){

add(nd[i].i);

ans+=(1ll*i-getnum(nd[i].i));//已插入i个数,getnum[nd[i].i]是比nd[i].i小的数的个数i-getnum[nd[i].i]就是i个数前比他大的数

}

printf("%lld\n",ans);

}

return 0;

}

归并排序:

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#define mem(a,b) memset(a,b,sizeof(a))

#define MOD 100000007

#define ll long long

#define INF 0x3f3f3f3f

const double pi = acos(-1.0);

const int Maxn=50000;

using namespace std;

inline int scan()

{

int x=0,c=1;

char ch=' ';

while((ch>'9'||ch

while(ch=='-')c*=-1,ch=getchar();

while(ch<='9'&&ch>='0')x=x*10+ch-'0',ch=getchar();

return x*c;

}

int c[500010];

vectorvec;

int n;

ll ans;

void mergersort(int l,int r){

if(l==r){

return ;

}

int mid=(l+r)>>1;

mergersort(l,mid);

mergersort(mid+1,r);

vec.clear();

int q=l,p=mid+1;

while(q<=mid&&p<=r){

if(c[q]<=c[p]){

vec.push_back(c[q++]);

}else{

vec.push_back(c[p++]);

ans+=(mid-q+1);///l~mid中剩余数的个数就是mid-q+1,而如果c[q]>c[p],那c[p]就要交换mid-q+1次

}

}

while(q<=mid) vec.push_back(c[q++]);

while(p<=r) vec.push_back(c[p++]);

q=l;

for(int i=0;i

c[q++]=vec[i];

}

}

int main(){

while(scanf("%d",&n)&&n){

ans=0;

mem(c,0);

for(int i=1;i<=n;i++){

scanf("%d",&c[i]);

}

mergersort(1,n);

printf("%lld\n",ans);

}

return 0;

}

标签:归并,ch,return,树状,int,ll,define,include,逆序

来源: https://www.cnblogs.com/liuzuolin/p/10827554.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值