对1~n的乱序数冒泡排序过程,求解每一个数能到达的最左和最右的位置差
本质就是求解每一个数右边有多少小于他的数,加上现在的位置既是能到达的最右位置,最左位置很直观
用树状数组或者线段树
渣渣现在才发现代码里的线段树比硬来时间复杂度低
线段树代码
#include <iostream> #include <map> #include <math.h> #include <algorithm> #include <vector> #include <cstdlib> #include <cstdio> #include <cstring> #include <set> #include<stdio.h> using namespace std; const int N=1e5+10; const int M=1e9+7; int g[N*4],t,cnt,n,a[N],num[N],b[N]; void buildtree(int l,int r,int u)//建树 { if(l==r) { g[u]=0; return ; } int mid=(l+r)/2; buildtree(l,mid,u*2); buildtree(mid+1,r,u*2+1); g[u]=0; } int query(int l,int r,int x,int y,int cnt)//查询 { if(l>=x&&r<=y) return g[cnt]; int mid=(l+r)/2; int k1=0,k2=0; if(mid>=x) k1=query(l,mid,x,y,cnt*2); if(mid<y) k2=query(mid+1,r,x,y,cnt*2+1); return k1+k2; } void update(int l,int r,int x,int cnt)//更新 { if(l==x&&l==r) { g[cnt]=1; return ; } int mid=(l+r)/2; if(x<=mid){ update(l,mid,x,cnt*2); g[cnt]+=1; } if(x>mid){ update(mid+1,r,x,cnt*2+1); g[cnt]+=1; } } int main() { freopen("in.txt","r",stdin); cin>>t; int cas=0; while(t--) { cas++; scanf("%d",&n); int i; buildtree(1,n,1); for(i=1; i<=n; i++) scanf("%d",&a[i]); for(i=n; i>0; i--) { if(a[i]==1) num[i]=0; else num[i]=query(1,n,1,a[i]-1,1); //cout<<"r"<<endl; update(1,n,a[i],1); //cout<<"r"<<endl; //cout<<num[i]<<" "; } printf("Case #%d: ",cas); for(i=1; i<=n; i++) { int k1=num[i]+i; int k2=i; int k3=a[i]; b[a[i]]=max(max(k1,k2),k3)-min(min(k1,k2),k3); } for(i=1; i<n; i++) printf("%d ",b[i]); printf("%d ",b[n]); } return 0; }
树状数组
#include <iostream> #include <map> #include <math.h> #include <algorithm> #include <vector> #include <cstdlib> #include <cstdio> #include <cstring> #include <set> #include<stdio.h> using namespace std; const int N=100010; const int M=1e9+7; int a[N],tree[N],t,n,b[N],num[N]; void add(int k,int num){//对k位置的数加上num while(k<=n){ tree[k]+=num; k+=k&(-k); } } int read(int k){//查询一到k位置a[i]的和 int sum=0; while(k){ sum+=tree[k]; k-=k&(-k); } return sum; } int main() { // freopen("in.txt","r",stdin); cin>>t; int cas=0; while(t--){ cas++; memset(tree,0,sizeof(tree)); int i; scanf("%d",&n); for(i=1;i<=n;i++){ scanf("%d",&a[i]); } for(i=1;i<=n;i++){ if(a[i]==1) num[1]=0; else num[a[i]]=read(a[i]); add(a[i],1); } //cout<<"2"<<endl; for(i=1;i<=n;i++){ int min1=min(i,a[i]); int max1=max(i+a[i]-1-num[a[i]],a[i]); b[a[i]]=max1-min1; } printf("Case #%d: ",cas); for( i = 1 ; i <=n ; i ++){ if(i==n) printf("%d ",b[i]); else printf("%d ",b[i]); } } return 0; }