HDU 1394 树状数组||线段树
2013-10-14 19:27
363 查看
给出一个序列,from 0 to n-1,如果2个数满足下标小的值大,那么逆序数的和+1
可以把最左边的数 放到最右边,按此规则变换,求过程中产生的最小的逆序数的和
思路
先求出原始序列的逆序数的和,然后如果每次移动最左边的数到最右边,那么逆序数的变化是可以预知的
因为由于最左边的数产生的逆序数 为他右边比他小的数个数,而除了他自己,剩下的数都在他右边,一共n-1个,比他小的数的个数就是str[i];
而最左边的数放到最右边所新产生的逆序数也是可以预知的,为(把最左边放到最右边之后)他左边比他大的数,一共n-1个,比他大的个数是n-1-str[i];
求原始序列的时候,只需要统计一下在这个数之前出现过的比他小的数的个数x,那么他后面比他小的个数即str[i]-x;
树状数组 和线段树都可以很方便的统计出x.
需要注意的就是 数字的值从0到n-1;
线段树版...算是第一个纯手写的>_<了
单点更新+区间查询
树状数组 要注意 str[i]值要+1,因为无法处理=0的状况
可以把最左边的数 放到最右边,按此规则变换,求过程中产生的最小的逆序数的和
思路
先求出原始序列的逆序数的和,然后如果每次移动最左边的数到最右边,那么逆序数的变化是可以预知的
因为由于最左边的数产生的逆序数 为他右边比他小的数个数,而除了他自己,剩下的数都在他右边,一共n-1个,比他小的数的个数就是str[i];
而最左边的数放到最右边所新产生的逆序数也是可以预知的,为(把最左边放到最右边之后)他左边比他大的数,一共n-1个,比他大的个数是n-1-str[i];
求原始序列的时候,只需要统计一下在这个数之前出现过的比他小的数的个数x,那么他后面比他小的个数即str[i]-x;
树状数组 和线段树都可以很方便的统计出x.
需要注意的就是 数字的值从0到n-1;
线段树版...算是第一个纯手写的>_<了
单点更新+区间查询
#include<stdio.h> #define lson l,mid,rt<<1 #define rson mid+1,r,rt<<1|1 #include<string.h> #include<algorithm> using namespace std; int sum[5005<<2]; void pushUP(int rt){ sum[rt]=sum[rt<<1]+sum[rt<<1|1]; } int query(int L,int R,int l,int r,int rt){ if(L<=l&&r<=R){ return sum[rt]; } int mid=(l+r)>>1; int sum=0; if(L<=mid)sum+=query(L,R,lson); if(mid<R)sum+=query(L,R,rson); return sum; } void update(int x,int l,int r,int rt){ if(l==r){ sum[rt]++; return ; } int mid=(l+r)>>1; if(x<=mid)update(x,lson); if(x>mid)update(x,rson); pushUP(rt); } int str[5005]; int main(){ int n,tp,ans; while(scanf("%d",&n)!=EOF){ tp=ans=0; memset(sum,0,sizeof(sum)); for(int i=0;i<n;i++){ scanf("%d",&str[i]); tp+=str[i]-query(0,str[i],0,n-1,1); update(str[i],0,n-1,1); }ans=tp; for(int i=0;i<n;i++){ tp=tp-str[i]+(n-1-str[i]); ans=min(tp,ans); }printf("%d\n",ans); }return 0; }
树状数组 要注意 str[i]值要+1,因为无法处理=0的状况
#include<stdio.h> #include<string.h> #include<algorithm> using namespace std; int c[5005],n; int lowbit(int x){ return -x&x; } int get(int x){ int ans=0; while(x>0){ ans+=c[x],x-=lowbit(x); }return ans; } void add(int x,int d){ while(x<=n){ c[x]+=d,x+=lowbit(x); } } int main(){ int str[5005],tp; while(scanf("%d",&n)!=EOF){ tp=0; memset(c,0,sizeof(c)); for(int i=0;i<n;i++){ scanf("%d",&str[i]); str[i]++; tp+=i-get(str[i]); add(str[i],1); }int ans=tp; for(int i=0;i<n;i++){ tp=tp-str[i]+1+(n-str[i]); ans=min(tp,ans); } printf("%d\n",ans); }return 0; }
相关文章推荐
- [hdu]1394 Minimum Inversion Number -- 暴力求逆序、树状数组求逆序、线段树求逆序、归并排序求逆序
- HDU 1394 (树状数组 & 线段树 两种做法)
- 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(树状数组、线段树)
- hdu 1394 Minimum Inversion Number(树状数组,线段树)
- HDU - 1394 Minimum Inversion Number(树状数组 or 线段树)
- HDU 1541 Stars(树状数组||线段树)
- HDU1394 Minimum Inversion Number (树状数组)
- HDU 1556 Color the ball (线段树|树状数组,区间更新)
- POJ 2892 Tunnel Warfare || HDU 1540(树状数组+二分 || 线段树的单点更新+区间查询)
- hdu 1166 树状数组 线段树入门
- HDU - 1166 - 敌兵布阵(树状数组、线段树)
- hdu 1166 敌兵布阵(数据结构:树状数组||线段树)
- hdu-1394-Minimum Inversion Number(树状数组)
- HDU 1166 敌兵布阵(树状数组、sum型线段树)
- HDU 1394 Minimum Inversion Number (离散化 + 树状数组 求逆序对)
- hdu_2795_线段树入门_线段树由树状数组转坑原本数组模拟