1. 程式人生 > >hdu1394求逆序對--hdu5592還原逆序對

hdu1394求逆序對--hdu5592還原逆序對

(有任何問題歡迎留言或私聊 && 歡迎交流討論哦

 讀入一個數字,線段樹求比他大的數的個數,累加,更新。

AC程式碼:

#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#define mm0(a) memset((a),0,sizeof((a)))
#define lson rt<<1
#define rson rt<<1|1
#define lsonl rt<<1,l,m
#define rsonr rt<<1|1,m+1,r using namespace std; typedef long long LL; const int N = 1e6+5; int n,m; struct lp{ int l,r; int sum; }cw[N<<2]; int ar[N],br[N]; void build(int rt,int l,int r){ cw[rt].l=l;cw[rt].r=r; cw[rt].sum=0; if(l==r){ return; } int m=(l+r)>>1
; build(lsonl); build(rsonr); } void update(int rt,int p){ cw[rt].sum++; if(cw[rt].l==cw[rt].r){ return; } int m=(cw[rt].l+cw[rt].r)>>1; if(p<=m){ update(lson,p); }else{ update(rson,p); } } int query(int rt,int L,int R){ if(L>R)return
0; if(L<=cw[rt].l&&cw[rt].r<=R){ return cw[rt].sum; } int m=(cw[rt].l+cw[rt].r)>>1; if(L>m){ return query(rson,L,R); }else if(R<=m){ return query(lson,L,R); }else{ return query(lson,L,m)+query(rson,m+1,R); } } int main(){ while(~scanf("%d",&n)){ for(int i=0;i<n;++i){ scanf("%d",&ar[i]); ar[i]++; } build(1,1,n); int ans=0; for(int i=0;i<n;++i){ br[i]=query(1,ar[i]+1,n); ans+=br[i]; update(1,ar[i]); } int ret=ans; for(int i=0;i<n;++i){ ar[i]--; ans=min(ans,ret-(ar[i])+(n-ar[i]-1)); ret=ret-(ar[i])+(n-ar[i]-1); } printf("%d\n",ans ); } return 0; } //提一下樹狀陣列求逆序對寫法: //不針對本題 #include<bits/stdc++.h> #define lowbit(x) (x&(-x)) using namespace std; typedef long long LL; const int N = 1e5+7; int n,q,tot; int ar[N],bit[N]; void add(int x){ while(x<=n){ bit[x]++; x += lowbit(x); } } int query(int x){ int sum=0; while(x){ sum+=bit[x]; x-=lowbit(x); } return sum; } int main(){ int tim; scanf("%d", &tim); while(tim--){ scanf("%d", &n); for(int i=1;i<=n;++i){ scanf("%d", &ar[i]); } LL all=0; memset(bit,0,sizeof(bit)); for(int i=1;i<=n;++i){ int p = ar[i]; int tmp = query(p); all+=tmp; add(p); } all=n*1LL*(n-1)/2-all; printf("%lld\n", all); } return 0; }

已知有字首和逆序數個數陣列p。

建權值線段樹,記錄區間內權值的個數。
p[i]-p[i-1]表示前i個數中有多少個數比它大。那麼它就是第(i-(p[i]-p[i-1]))個數。
每確定一個數,減去該權值。

AC程式碼:

#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#define lson rt<<1
#define rson rt<<1|1
#define lsonl rt<<1,l,m
#define rsonr rt<<1|1,m+1,r
using namespace std;
typedef long long LL;
const int N = 1e6+5;
int n,m;
struct lp{
    int l,r;
    int sum,val;
}cw[N<<2];
int ar[N],ans[N];
void build(int rt,int l,int r){
    cw[rt].l=l;cw[rt].r=r;
    cw[rt].sum=r-l+1;
    if(l==r){
        cw[rt].val=l;
        return;
    }
    int m=(l+r)>>1;
    build(lsonl);
    build(rsonr);
}
void update(int rt,int p){
    cw[rt].sum--;
    if(cw[rt].l==cw[rt].r){
        return;
    }
    int m=(cw[rt].l+cw[rt].r)>>1;
    if(p<=m){
        update(lson,p);
    }else{
        update(rson,p);
    }
}
int query(int rt,int p){
    if(cw[rt].l==cw[rt].r){
        return cw[rt].val;
    }
    int m=(cw[rt].l+cw[rt].r)>>1;
    if(p<=cw[lson].sum){
        return query(lson,p);
    }else{
        return query(rson,p-cw[lson].sum);
    }
}
int main(){
    int tim;
    scanf("%d",&tim);
    while(tim--){
        scanf("%d",&n);
        ar[0]=0;
        build(1,1,n);
        for(int i=1;i<=n;++i){
            scanf("%d",&ar[i]);
        }
        for(int i=n;i>=1;--i){
            ans[i]=query(1,i-(ar[i]-ar[i-1]));
            update(1,ans[i]);
        }
        for(int i=1;i<n;++i){
            printf("%d ",ans[i] );
        }
        printf("%d\n",ans[n] );
    }
    return 0;
}