2015 Multi-University Training Contest 4 (hdu5338 ZZX and Permutations)线段树(好)

ZZX and Permutations

Problem Description

ZZX likes permutations.

ZZX knows that a permutation can be decomposed into disjoint cycles(see https://en.wikipedia.org/wiki/Permutation#Cycle_notation). For example:
145632=(1)(35)(462)=(462)(1)(35)=(35)(1)(462)=(246)(1)(53)=(624)(1)(53)……
Note that there are many ways to rewrite it, but they are all equivalent.
A cycle with only one element is also written in the decomposition, like (1) in the example above.

Now, we remove all the parentheses in the decomposition. So the decomposition of 145632 can be 135462,462135,351462,246153,624153……

Now you are given the decomposition of a permutation after removing all the parentheses (itself is also a permutation). You should recover the original permutation. There are many ways to recover, so you should find the one with largest lexicographic order.

Input

First line contains an integer t, the number of test cases.
Then t testcases follow. In each testcase:
First line contains an integer n, the size of the permutation.
Second line contains n space-separated integers, the decomposition after removing parentheses.

n105 . There are 10 testcases satisfying n105 , 200 testcases satisfying n≤1000.

Output

Output n space-separated numbers in a line for each testcase.
Don’t output space after the last number of a line.

Sample Input

2
6
1 4 5 6 3 2
2
1 2

Sample Output

4 6 2 5 1 3
2 1
这个题看了好半天,就是看不明白,后来在hdu5338 的帮助下终于明白要干啥了,于是就比较清楚了
按照第一个样例解释一下题意:
(1 4 5)(6 3 2)这样加括号之后表示,数字4放到位置1,数字5放到位置4,数字1放到位置5,后面同理。所以按照位置从小到大枚举,枚举位置1的时候,你需要求谁来替换掉数字1,也就是把谁放到位置1上,那么就是从数字1所在的位置后面那个数,或者他前面找一个最大的,这两个中大的放到位置1上,因为是按照位置枚举的,所以保证字典序是最大的。
hdu5338
hdu5338

#include<iostream>
#include<cstdio>
#include<string>
#include<cstring>
#include<vector>
#include<cmath>
#include<queue>
#include<stack>
#include<map>
#include<set>
#include<algorithm>
using namespace std;
typedef long long LL;
const int maxn=100010;
const int maxm=1010;
const int MOD=1e9+7;
const int INF=0x3f3f3f3f;
int N;
int a[maxn];
int pos[maxn],vis[maxn];
set<int> sp;
int ans[maxn];
struct IntervalTree
{
    int maxv[maxn<<2];
    void build(int o,int l,int r)
    {
        if(l==r)
        {
            maxv[o]=a[l];
            return ;
        }
        int mid=(l+r)>>1;
        build(o<<1,l,mid);
        build(o<<1|1,mid+1,r);
        pushup(o);
    }
    void pushup(int o)
    {
        maxv[o]=max(maxv[o<<1],maxv[o<<1|1]);
    }
    void update(int o,int l,int r,int pos,int val)
    {
        if(l==r)
        {
            maxv[o]=val;
            return ;
        }
        int mid=(l+r)>>1;
        if(pos<=mid)update(o<<1,l,mid,pos,val);
        else update(o<<1|1,mid+1,r,pos,val);
        pushup(o);
    }
    int query(int o,int l,int r,int q1,int q2)
    {
        if(q1<=l&&r<=q2)
        {
            return maxv[o];
        }
        int mid=(l+r)>>1;
        int ans=0;
        if(q1<=mid)ans=max(ans,query(o<<1,l,mid,q1,q2));
        if(q2>mid)ans=max(ans,query(o<<1|1,mid+1,r,q1,q2));
        return ans;
    }
}tree;
int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d",&N);
        for(int i=1;i<=N;i++)
        {
            scanf("%d",&a[i]);
            pos[a[i]]=i;
        }
        sp.clear();
        tree.build(1,1,N);
        memset(ans,-1,sizeof(ans));
        memset(vis,0,sizeof(vis));
        for(int i=1;i<=N;i++)
        {
            if(ans[i]!=-1)continue;
            int l=1;
            if(!sp.empty())
            {
                auto it=sp.lower_bound(pos[i]);//表示他前面能用的数的界限
                if(it!=sp.begin())
                {
                    it--;
                    l=(*it)+1;
                }
            }
            int maxv=tree.query(1,1,N,l,pos[i]);
            if(pos[i]!=N&&!vis[a[pos[i]+1]]&&maxv<a[pos[i]+1])
            {
                ans[i]=a[pos[i]+1];
                tree.update(1,1,N,pos[i]+1,-1);
            }
            else
            {
                ans[i]=maxv;
                vis[maxv]=1;
                for(int j=pos[maxv];j<pos[i];j++)
                    ans[a[j]]=a[j+1];
                sp.insert(pos[i]);
            }
        }
        for(int i=1;i<=N;i++)
        {
            printf("%d",ans[i]);
            if(i==N)printf("\n");
            else printf(" ");
        }
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值