HDU-1394 Minimum Inversion Number(线段树)
2017-08-10 15:48
357 查看
四处翻了翻解题报告,总结需解决两点
1、求初始序列逆序对数和。
这里可以使用线段树或者树状数组。
使用原理就是:利用线段树或者树状数组将 [0 - n-1]排开。
入读一个数时,
1)向后查询。例如读入3 , 那么就看看4 5 6 7 8 ….是否有之前输入过的。
然后累加起来 ,这便是初态的逆序对数。
2)单点更新,找到3这个点,标记一下 方便下次输入查询。
以线段树为例, 初始化线段树各个点sum[rt]=0 。读入一个数a[i]时
向后查询,s+=query(a[i],n-1,0,n-1,1); 前面两位参数是从a[i]向后查询的意思。
用s累加起来
再单点更新,使sum[a[i]]++。 update(a[i],1,0,n-1,1); 意思是从 [0,n-1]区间中 找到a[i] 这个点,进行+1操作
2、交换后的逆序对数, 跟上一个状态有关,s=s-a[i]+(n-1-a[i]); ;也就是这么一个公式带入具体数据推一推。
线段树实现代码如下:
个人理解一下使用线段树和树状数组区别,树状数组由于其特性 管理的数只能从 1开始。因此读入时每位i+1(如有错误请指出)
树状数组实现:
(如有错误,欢迎支持)
1、求初始序列逆序对数和。
这里可以使用线段树或者树状数组。
使用原理就是:利用线段树或者树状数组将 [0 - n-1]排开。
入读一个数时,
1)向后查询。例如读入3 , 那么就看看4 5 6 7 8 ….是否有之前输入过的。
然后累加起来 ,这便是初态的逆序对数。
2)单点更新,找到3这个点,标记一下 方便下次输入查询。
以线段树为例, 初始化线段树各个点sum[rt]=0 。读入一个数a[i]时
向后查询,s+=query(a[i],n-1,0,n-1,1); 前面两位参数是从a[i]向后查询的意思。
用s累加起来
再单点更新,使sum[a[i]]++。 update(a[i],1,0,n-1,1); 意思是从 [0,n-1]区间中 找到a[i] 这个点,进行+1操作
2、交换后的逆序对数, 跟上一个状态有关,s=s-a[i]+(n-1-a[i]); ;也就是这么一个公式带入具体数据推一推。
线段树实现代码如下:
#include <iostream> #include <cstdio> #define lson l,m,rt<<1 #define rson m+1,r,rt<<1|1 #define maxn 55555 using namespace std; int sum[maxn<<2]; int cnt=1; void PushUp(int rt) { sum[rt]=sum[rt*2]+sum[rt*2+1]; } void build(int l,int r,int rt) { sum[rt]=0; if(l==r) return ; int m=(l+r)/2; build(lson); build(rson); PushUp(rt); } void update(int p,int add,int l,int r,int rt)///单点更新, 为了找到p点,用了二分 { if(l==r) { sum[rt]+=add; return; } int m=(l+r)/2; if(p<=m) update(p,add,lson); else update(p,add,rson); PushUp(rt);///不忘回溯 } int query(int L,int R,int l,int r,int rt)///查询某区间[L,R]的值 { if(l==r) return sum[rt]; int m=(l+r)/2; int ret=0; if(L<=m) ret+=query(L,R,lson);///找到是【L,R】的子区间 if(R>m) ret+=query(L,R,rson); return ret; } int main() { int n; while(~scanf("%d",&n)) { int s=0; int a[10000]; build(0,n+1,1); for(int i=1; i<=n; i++) { scanf("%d",&a[i]); s+= query(a[i],n-1,0,n-1,1); update(a[i],1,0,n-1,1); } int ans=s; for(int i=1; i<n; i++) { s += n - a[i] - a[i] - 1; ans=min(ans,s); } cout<<ans<<endl; } return 0; }
个人理解一下使用线段树和树状数组区别,树状数组由于其特性 管理的数只能从 1开始。因此读入时每位i+1(如有错误请指出)
树状数组实现:
#include<cstdio> #include<cstring> #include<algorithm> using namespace std; const int MAXN=5000; int c[MAXN+1]; int lowbit(int x) { return x&(-x); } int sum(int x) { int res=0; while(x>0) { res+=c[x]; x-=lowbit(x); } return res; } void add(int x,int v) { while(x<=MAXN) { c[x]+=v; x+=lowbit(x); } } int a[MAXN]; int main() { int n; while(scanf("%d",&n)==1) { int counter=0;//计算逆序 memset(c,0,sizeof(c)); for(int i=1;i<=n;i++) { scanf("%d",&a[i]); a[i]++;//标记 counter+= sum(n)-sum(a[i]);///读入是0 ,但是我们要的是1 。 add(a[i],1); } int ans=counter;//ans保存最终结果 for(int i=1;i<n;i++) { counter +=n-2*a[i]+1; ans = min(ans,counter); } printf("%d\n",ans); } }
(如有错误,欢迎支持)
相关文章推荐
- HDU 1394 Minimum Inversion Number (线段树 求逆序对)
- HDU 1394 Minimum Inversion Number.(线段树)
- hdu 1394 Minimum Inversion Number(树状数组,线段树)
- HDU 1394 Minimum Inversion Number 树状数组/线段树
- hdu1394--Minimum Inversion Number(线段树求逆序数,纯为练习)
- 【线段树I:点修改+区间查询】hdu 1394 Minimum Inversion Number
- HDU_1394 Minimum Inversion Number(线段树)
- HDU 1394(线段树) Minimum Inversion Number
- HDU 1394 Minimum Inversion Number (线段树 单点更新 求逆序数)
- hdu1394-Minimum Inversion Number(线段树)
- HDU 1394——Minimum Inversion Number——————【线段树单点增减、区间求和】
- HDU1394-Minimum Inversion Number(线段树单点更新)
- HDU 1394 Minimum Inversion Number 线段树
- hdu 1394/哈理工oj 1250 Minimum Inversion Number【线段树过】
- HDU1394——线段树——Minimum Inversion Number
- HDU 1394 Minimum Inversion Number(树状数组||线段树)
- hdu 1394 Minimum Inversion Number(线段树-单点更新)
- HDU 1394 Minimum Inversion Number(线段树求逆序对数)
- HDU 1394 Minimum Inversion Number(用规律取代线段树)
- HDU-1394 Minimum Inversion Number 线段树|树状数组