对于数列插空问题, 常用线段树来处理,从后往前,因为后面的数的位置是不会改变的,对于i的位置 ,如果i位置上已经有数了,那么就找i之后第一个空位,num【i】=k纪录i所放的位置, 然后就按照hdu1025做法一样了 ,
#include<stdio.h> #include<string.h> #include<iostream> using namespace std; #define LL(x) (x<<1) #define RR(x) ((x<<1)|1) int num[100010],id[100010]; int mark[4*100010]; int deal(int L,int R,int point) { mark[point]=R-L+1; if(R==L) return 0; int mid=(L+R)/2; deal(L,mid,LL(point)); deal(mid+1,R,RR(point)); return 0; } int find(int L,int R,int pos,int point,int k) { mark[point]--; if(L==R) { num[k]=L; return 0; } int mid=(L+R)/2; if(pos<=mark[LL(point)]) find(L,mid,pos,LL(point),k); else find(mid+1,R,pos-mark[LL(point)],RR(point),k); return 0; } int main() { int T,i,j,n,d=1; scanf("%d",&T); while(T--) { scanf("%d",&n); for(i=1;i<=n;i++) { scanf("%d",&id[i]); id[i]++; } deal(1,n,1); for(i=n;i>=1;i--) { find(1,n,id[i],1,i); } //for(i=1;i<=n;i++) //printf("%d ",num[i]); //printf("\n"); int dis[100010],len=1; dis[1]=num[1]; printf("Case #%d:\n1\n",d++); for(i=2;i<=n;i++) { if(num[i]>dis[len]) { len++; dis[len]=num[i]; } else { int left=1,right=len; //int flash=0; while(left<=right) { int mid=(left+right)/2; if(dis[mid]<num[i]) left=mid+1; else right=mid-1; } //if(flash) dis[1]=num[i]; dis[left]=num[i]; } printf("%d\n",len); } printf("\n"); } return 0; }
时间: 2024-09-30 06:18:48