HDU 1394 Minimum Inversion Number 線段樹+思維
阿新 • • 發佈:2019-02-07
去年用樹狀陣列做過這道題,今年思路一樣,多虧這是個n的全排列,每動一個數,你知道會有多少數發生改變。第五次手寫線段樹,寫過了高興。
#include<iostream> #include<cstdio> #include<string.h> #include<algorithm> #include<cmath> #include<map> using namespace std; int a[5010]; struct node { int l,r; int sum; int lazy; void update(int v) { sum+=(r-l+1)*v; lazy+=v; } }; node tree[5010*4]; inline void push_down(int rt) { int lazyval=tree[rt].lazy; tree[rt*2].update(lazyval); tree[rt*2+1].update(lazyval); tree[rt].lazy=0; } inline void push_up(int rt) { tree[rt].sum=tree[rt*2].sum+tree[rt*2+1].sum; } inline void build_tree(int l,int r,int rt) { tree[rt].l=l; tree[rt].r=r; tree[rt].sum=tree[rt].lazy=0; if (l==r) tree[rt].sum=0; else { int mid=(r+l)/2; build_tree(l,mid,rt*2); build_tree(mid+1,r,rt*2+1); push_up(rt); } //cout<<"l="<<l<<" r="<<r<<" rt="<<rt<<" sum="<<tree[rt].sum<<endl; } inline void update(int l,int r,int v,int rt) { int L=tree[rt].l; int R=tree[rt].r; if (l<=L && R<=r) tree[rt].update(v); else { push_down(rt); int mid=L+R>>1; if (l<=mid) update(l,r,v,rt*2); if (mid<r) update(l,r,v,rt*2+1); push_up(rt); } } inline int query(int l,int r,int rt) { int L=tree[rt].l; int R=tree[rt].r; if (l<=L && r>=R) { return tree[rt].sum; } else { push_down(rt); int mid=L+R>>1; int res=0; if (l<=mid) res+=query(l,r,rt*2); if (r>mid) res+=query(l,r,rt*2+1); push_up(rt); //cout<<"l="<<l<<" r="<<r<<" rt="<<rt<<" L="<<L<<" R="<<R<<endl; //cout<<"res="<<res<<endl; return res; } } int n; int main() { while (~scanf("%d",&n)) { for (int i=1; i<=n; i++) scanf("%d",&a[i]); build_tree(1,n,1); int tm=0; int ans; for (int i=1; i<=n; i++) { tm+=query(1,n-a[i],1); update(n-a[i],n-a[i],1,1); } ans=tm; for (int i=1; i<=n-1; i++) { update(n-a[i],n-a[i],-1,1); tm+=query(1,n-a[i],1)-a[i]; update(n-a[i],n-a[i],1,1); if (ans>tm) ans=tm; } printf("%d\n",ans); } return 0; }