题目链接:点击打开链接
题目大意:给出一个序列,分成若干个置换群,要求最终的序列的字典序最大。
要求字典序最大,那么从1开始向后遍历,尽量放较大的数
给出序列a1 a2 a3 ,,, ai an
对于第i个数来说,可能有三种情况,第一种向前找能到达的序列的最大值ak,那么ak到ai就是一个轮换;第二种ai自身,或者是以ai结尾;第三种由i想后找,对于轮换来说,只能在i位置放ai+1,那么ai和ai+1只能构成轮换的一部分;在这三种可以放的值中选出最大值,也就是第i个位置能放的数
注意
1、当选自身是,可能是自己一个数为一个轮换,也可能是一个轮换的结尾,那么i位置要放这个轮换的第一个数。
2、对于第三种情况来说,只能确定轮换的一部分,不能确定一个完整的轮换,这些轮换的片段可以连接起来,并且可以通过第二种情况是轮换完整。
#include <cstdio> #include <cstring> #include <queue> #include <set> #include <vector> #include <cmath> #include <map> #include <stack> #include <algorithm> using namespace std ; #pragma comment(linker, "/STACK:102400000,102400000") #define LL __int64 #define INF 0x3f3f3f3f #define PI acos(-1.0) const int mod = 1e9+7 ; const double eqs = 1e-9 ; #define maxn 100000+10 #define root 1,n,1 #define int_rt int l,int r,int rt #define lson l,(l+r)/2,rt<<1 #define rson (l+r)/2+1,r,rt<<1|1 int cl1[maxn<<2] , cl2[maxn<<2] ; int a[maxn] , ans[maxn] , vis[maxn] , id[maxn] , flag[maxn]; void push_up1(int rt) { cl1[rt] = max(cl1[rt<<1],cl1[rt<<1|1]) ; return ; } void create(int_rt) { if( l == r ) { scanf("%d", &a[l]) ; cl1[rt] = a[l] ; id[ a[l] ] = l ; return ; } create(lson) ; create(rson) ; push_up1(rt) ; return ; } void update1(int k,int_rt) { if( l == r ) { cl1[rt] = -1 ; return ; } if( (l+r)/2 >= k ) update1(k,lson) ; else if( k > (l+r)/2 ) update1(k,rson) ; else return ; push_up1(rt) ; } int query1(int ll,int rr,int_rt) { if( rr < l || ll > r ) return -1 ; if( ll <= l && rr >= r ) return cl1[rt] ; return max( query1(ll,rr,lson) , query1(ll,rr,rson) ) ; } void push_up2(int rt) { cl2[rt] = max(cl2[rt<<1] , cl2[rt<<1|1]) ; return ; } void update2(int k,int_rt) { if( l == r ) { cl2[rt] = l ; return ; } if( k <= (l+r)/2 ) update2(k,lson) ; else if( k > (l+r)/2 ) update2(k,rson) ; else return ; push_up2(rt) ; return ; } int query2(int ll,int rr,int_rt) { if( rr < l || ll > r ) return -1 ; if( ll <= l && rr >= r ) return cl2[rt] ; return max( query2(ll,rr,lson) , query2(ll,rr,rson) ) ; } int main() { int t , n , i , j ; int k1 , k2 , k3 ; int l , r ; //freopen("1012.in","r",stdin) ; // freopen("23333.txt","w",stdout) ; scanf("%d", &t) ; while( t-- ) { memset(cl1,-1,sizeof(cl1)) ; memset(cl2,-1,sizeof(cl2)) ; memset(vis,0,sizeof(vis)) ; memset(flag,0,sizeof(flag)) ; scanf("%d", &n) ; create(root) ; a[n+1] = -1 ; for(i = 1 ; i <= n ; i++) { if(i == 715) i = 715 ; if( vis[i] == 1 ) continue ; l = query2(1,id[i]-1,root) ; l++ ; if( l <= 0 ) l = 1 ; k1 = query1(l,id[i]-1,root) ; if( vis[i] == 0 ) k2 = i ; else if( vis[i] < 0 && !vis[ -vis[i] ] ) k2 = -vis[i] ; else k2 = -1 ; k3 = a[ id[i]+1 ] ; if( vis[ a[ id[i]+1 ] ] == 1 ) k3 = -1 ; if( k1 > k2 && k1 > k3 ) { ans[i] = k1 ; vis[k1] = 1 ; for( j = id[k1] ; j < id[i] ; j++ ) { ans[ a[j] ] = a[j+1] ; vis[ a[j+1] ] = 1 ; } update2(id[i],root) ; } else if( k2 > k1 && k2 > k3 ) { ans[i] = k2 ; vis[ ans[i] ] = 1 ; flag[ flag[ k2 ] ] = 0 ; flag[k2] = 0 ; update2(id[i],root) ; } else if( k3 > k1 && k3 > k2 ) { if( vis[i] == 0 ) { vis[ k3 ] = -i ; ans[i] = k3 ; flag[k3] = i ; flag[i] = k3 ; } else { if( flag[ k3 ] ) { ans[i] = k3 ; vis[ k3 ] = 1 ; flag[ flag[k3] ] = flag[i] ; flag[ flag[i] ] = flag[k3] ; vis[ flag[k3] ] = vis[i] ; continue ; } else{ flag[k3] = flag[i] ; flag[flag[i]] = k3 ; vis[k3] = vis[i] ; ans[i] = k3 ; } } update1(id[i],root) ; update1(id[k3],root) ; } } for(i = 1 ; i < n ; i++) printf("%d ", ans[i]) ; printf("%d\n", ans[n]) ; } return 0 ; }