hdu5338(2015多校4)--ZZX and Permutations(置换群)

题目链接:点击打开链接

题目大意:给出一个序列,分成若干个置换群,要求最终的序列的字典序最大。

要求字典序最大,那么从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 ;
}

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-08-03 18:40:34

hdu5338(2015多校4)--ZZX and Permutations(置换群)的相关文章

hdu5338 ZZX and Permutations

hdu5338 ZZX and Permutations 非原创,来自多校题解 不是自己写的,惭愧ing…… 留着以后自己参考…… lower_bound {1,2,4,5} 询问 2,返回的是 2 ,询问3 返回的是 4 是大于等于元素的值 upper_bound {1,2,4,5} 询问2,返回4,询问3,返回4,是 大于 元素的值 题意:图论的知识 1 2 3 4 5 6 (1) 1 4 5 6 3 2 (2) (1)中 数字 1 的 位置没变 所以(1) 2 的为位置 编程了 4 ,4

hdu5338 ZZX and Permutations(贪心、线段树)

转载请注明出处: http://www.cnblogs.com/fraud/          ——by fraud ZZX and Permutations Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others)Total Submission(s): 181    Accepted Submission(s): 38 Problem Description ZZX likes

HDU 5338 ZZX AND PERMUTATIONS 线段树

链接 多校题解 胡搞... 题意太难懂了.. ZZX and Permutations Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others) Total Submission(s): 310    Accepted Submission(s): 83 Problem Description ZZX likes permutations. ZZX knows that a perm

HDOJ 5338 ZZX and Permutations 线段树+树状数组

[题意]: 给一个排列加上表示循环的括号,问如何让1到n的对应的字典序最大. 从1开始贪心每个数字可以往三个地方走,右边第一个,跳转到左边的某一个,和自己构成循环 对于走到右边第一个的情况,只要判断右边的那个有没有被占据就可以了,如果可以和右边的互换,那么需要在线段树中将右边的数置为0 跳转到左边的某一个,一个数如果跳转到左边的某一个则说明左边的那个是括号开头这个数是括号结尾,用一个线段树查询区间里的最大值,由于括号间是不能重叠的,所以需要用树状数组二分一下左边界.如果这个数是要跳转到左边的某个

HDU 5371 (2015多校联合训练赛第七场1003)Hotaru&#39;s problem(manacher+二分/枚举)

HDU 5371 题意: 定义一个序列为N序列:这个序列按分作三部分,第一部分与第三部分相同,第一部分与第二部分对称. 现在给你一个长为n(n<10^5)的序列,求出该序列中N序列的最大长度. 思路: 来自官方题解:修正了一些题解错别字(误 先用求回文串的Manacher算法,求出以第i个点为中心的回文串长度,记录到数组p中 要满足题目所要求的内容,需要使得两个相邻的回文串,共享中间的一部分,也就是说,左边的回文串长度的一半,要大于等于共享部分的长度,右边回文串也是一样. 因为我们已经记录下来以

HDU 5371 (2015多校联合训练赛第七场1003)Hotaru&amp;#39;s problem(manacher+二分/枚举)

pid=5371">HDU 5371 题意: 定义一个序列为N序列:这个序列按分作三部分,第一部分与第三部分同样,第一部分与第二部分对称. 如今给你一个长为n(n<10^5)的序列,求出该序列中N序列的最大长度. 思路: 来自官方题解:修正了一些题解错别字(误 先用求回文串的Manacher算法.求出以第i个点为中心的回文串长度.记录到数组p中 要满足题目所要求的内容.须要使得两个相邻的回文串,共享中间的一部分,也就是说.左边的回文串长度的一半,要大于等于共享部分的长度,右边回文串也

hdu 5288||2015多校联合第一场1001题

http://acm.hdu.edu.cn/showproblem.php?pid=5288 Problem Description OO has got a array A of size n ,defined a function f(l,r) represent the number of i (l<=i<=r) , that there's no j(l<=j<=r,j<>i) satisfy ai mod aj=0,now OO want to know ∑i

hdu5289||2015多校联合第一场1002贪心+RMQ

http://acm.hdu.edu.cn/showproblem.php?pid=5289 Problem Description Tom owns a company and he is the boss. There are n staffs which are numbered from 1 to n in this company, and every staff has a ability. Now, Tom is going to assign a special task to

hdu5348(2015多校5)--MZL&#39;s endless loop(搜索)

题目链接:点击打开链接 题目大意:给出n个点,m条无向边,现在要求将无向边变为有向边,要保证每个点的出度和入度的差不超过1 直接进行搜索,对每个点进行出度和入度的判断,如果出度大,就先进行反向的搜索(每搜索一条边u,v就认为这是一条v到u的有向边),反之,进行正向搜索(每搜到一条边u,v认为这是一条u到v的有向边),一直搜索到找不到边能继续为止. 注意: 1.已经使用过的边为了防止再次被遍历,可以修改head,head[u] = edge[i].next 2.注意自环,因为搜索是判断能不能继续向