题目点我点我点我
题目大意:给你一堆数,要只能在相邻交换成从小到大的序列。
思路:首先按照输入的数的下标用index记录
9 1 0 5 4
incex: 1 2 3 4 5
现在移动的方法可以这样,先找出最小的数,然后把它移到最前面,如0往前移动了2位,然后呢这时候我们就不必理会0了,以为已经是在自己的位置且在最前面,不影响后面的数;接下来呢就把1往前移动1位。如此类推呢,4移动2位,5移动了1位,所以最后答案是2+1+2+1=6次。
所以我们可以建一个线段树,把数组的下标放进去,并且每个结点都赋初值为1,如找0,那么0的index是3,则在[1,3)间记录有多少个数在0的前面,然后记录就把0这个结点值更新为0,即看作把0的这个结点删除了。所以建完树以后就按照大小排序好后逐个遍历且更新即可。
/* *********************************************** ┆ ┏┓ ┏┓ ┆ ┆┏┛┻━━━┛┻┓ ┆ ┆┃ ┃ ┆ ┆┃ ━ ┃ ┆ ┆┃ ┳┛ ┗┳ ┃ ┆ ┆┃ ┃ ┆ ┆┃ ┻ ┃ ┆ ┆┗━┓ 马 ┏━┛ ┆ ┆ ┃ 勒 ┃ ┆ ┆ ┃ 戈 ┗━━━┓ ┆ ┆ ┃ 壁 ┣┓┆ ┆ ┃ 的草泥马 ┏┛┆ ┆ ┗┓┓┏━┳┓┏┛ ┆ ┆ ┃┫┫ ┃┫┫ ┆ ┆ ┗┻┛ ┗┻┛ ┆ ************************************************ */ #include <stdio.h> #include <string.h> #include <iostream> #include <algorithm> #include <vector> #include <queue> #include <stack> #include <set> #include <map> #include <string> #include <math.h> #include <stdlib.h> using namespace std; #define inf 0x3f3f3f3f #define ll long long #define ull unsigned long long #define lson rt<<1, l, mid #define rson (rt<<1)|1,mid+1,r #define maxn 500002 int cnt[maxn*3],index[maxn],num[maxn]; bool cmp(int i,int j) { return num[i]<num[j]; } void update(int rt,int l,int r,int k,int value) { cnt[rt]+=value; if(l==r)return ; int mid=(l+r)>>1; if(k<=mid)update(lson,k,value); else update(rson,k,value); } int querry(int rt,int l,int r,int left,int right) { if(l>=left && r<=right) return cnt[rt]; int mid=(l+r)>>1; int ans=0; if(left<=mid)ans+=querry(lson,left,right); if(right>mid)ans+=querry(rson,left,right); return ans; } int main() { //freopen("in.txt","r",stdin); //freopen("out.txt","w",stdout); int n; while(~scanf("%d",&n),n) { ll ans=0; memset(cnt,0,sizeof cnt); memset(index,0,sizeof index); memset(num,0,sizeof num); for(int i=1;i<=n;i++) { scanf("%d",&num[i]); update(1,1,n,i,1); index[i]=i; } sort(index+1,index+1+n,cmp); for(int i=1;i<=n;i++) { ans+=(querry(1,1,n,1,index[i])-1); //这里注意的是会把本身的1都加进去,所以要减去 update(1,1,n,index[i],-1); } printf("%I64d\n",ans); } return 0; }