hdu 5338 ZZX and Permutations (贪心+线段树+二分)

来源:互联网 发布:淘宝定时上架有什么用 编辑:程序博客网 时间:2024/05/22 02:25

ZZX and Permutations

Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others)
Total Submission(s): 24    Accepted Submission(s): 2


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 n1000.
 

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
261 4 5 6 3 221 2
 

Sample Output
4 6 2 5 1 32 1
 

Source
2015 Multi-University Training Contest 4


题意是给你一个n个数以内的组合,每个数取1~n,告诉你一个循环变化标记又去掉括号后的数组,要你将这个数组还原成字典序最大的组合排列。
首先明确题意,例如1 4 5 6 3 2,用ans[i]表示答案位置i上的值,a[i]表示输入的数组,id[i]表示数值i在a[]中的位置;

求解时,ans[1]能取1或者4, 此时当然贪心取4就好了,对4这个值我们标记一下已经用过了,对ans[1]就得到答案了,位置1标记一下已经解出了答案了,但我们不确定位置4,因为4可能取1也可能取5,我们后面再讨论;

ans[2]能取1 5 6 3中的任意一个值,由于4这个值已经用过了,所以不能再用,贪心取最大值6,所以这个动态算最大值的时候要用到线段树维护最大值,因为最大值6在a[]中的i=4而2在a[]中的i=6,所以必然构成2<-6<-3<-2这种环,对于情况可以直接确定ans[2],ans[6],ans[3]的值,对于位置2,6,3标记已经解出答案了,对值6, 3, 2标记已经用过了,从线段树里删除(set l=4 r=6 value=0),对区间[4,6]标记已经确定了,不能从区间后面跨过去取区间前面的数,所以用个二分的结构把这个区间[l=4,r=6]丢进去,我用的map反正保证插入时是logn,树上二分的话也是logn,每次要用线段树查找最大值时,就不能跨过这些已经确定位置的区间,所以每次二分一下能够查找最大值的区间;

ans[3]解过答案,跳过就好;

ans[4]可以取1或者5,由于5更大且没被用过所以贪心取5,把5标记已经用过这个值了,从线段树里删掉5,把4这个位置标记一下,已经确定了;

ans[5]可以取线段树在区间[1,3]中找到的最大值,因为4和5都删掉了,也就是1还能取,那么就连上,对于这种把区间[1,3]就都定下来了,把区间[1,3]丢到二分的结构里;

ans[6]解过答案,跳过就好;

    #include <iostream>    #include <cstdio>    #include <cstdlib>    #include <cstring>    #include <algorithm>    #include <map>    using namespace std;    const int maxn = 100010;    typedef long long LL;    int a[maxn], vidx[maxn];    int vis[maxn], flg[maxn];    namespace SegmentTree{        int maxv[maxn<<2]; int setv[maxn<<2];        #define Lson o<<1        #define Rson o<<1|1        void pushup(int o){            maxv[o] = max(maxv[Lson], maxv[Rson]);        }        void build(int o, int l, int r){            int m = (l+r)>>1;            if(l == r){                maxv[o] = a[l];                setv[o] = -1;            }            else {                build(Lson, l, m);                build(Rson, m+1, r);                setv[o] = -1;                pushup(o);            }        }        void pushdown(int o){            if (setv[o] >= 0){                setv[Lson] = setv[Rson] = setv[o];                maxv[Lson] = maxv[Rson] = setv[o];                setv[o] = -1;            }        }        int v, ul, ur;        void update(int o, int l, int r){            if(l > r) return ;            if (ul <= l && r <= ur){                setv[o] = v;                maxv[o] = v;            }            else{                pushdown(o);                int m = (l+r)>>1;                if (ul <= m) update(Lson, l, m);                if (ur > m) update(Rson, m+1, r);                pushup(o);            }        }        int _max, ql, qr;        void query(int o, int l, int r){            if(l>r) return ;            if (setv[o] >= 0){                _max = max(_max, setv[o]);            }            else if (ql <= l && r <= qr){                _max = max(_max, maxv[o]);            }            else {                int m = (l+r)>>1;                pushdown(o);                if(ql <= m) query(Lson, l, m);                if(qr > m) query(Rson, m+1, r);            }        }    }    namespace BS{        typedef pair<int,int> seg;        #define l first        #define r second        #define MP make_pair        int n;        map<int,int> mp;        void init(){            mp.clear();        }        void add(int l, int r){            seg line = MP(l, r);            mp.insert(line);        }        int search(int v){            map<int,int>::iterator it = mp.upper_bound(v);            if (it == mp.begin()){                return 0;            }            else{                --it;                return it->r;            }        }    }    int ans[maxn];    void link(int l, int r){        for(int i=l; i<r; i++){            ans[a[i]] = a[i+1];        }        ans[a[r]] = a[l];    }    int main(){//        freopen("data.in", "r", stdin);        int T, n;        scanf("%d",&T);        while(T--){            scanf("%d", &n);            for(int i=1;i<=n;i++){                scanf("%d",&a[i]);                vidx[a[i]] = i;            }            memset(vis, 0, sizeof vis);            memset(flg, 0, sizeof flg);            SegmentTree::build(1,1,n);            BS::init();            for(int _i=1;_i<=n;_i++){                int i = vidx[_i];                if (vis[i]) continue;                int id = i, mx=0;                if(!flg[_i]) mx = _i;                SegmentTree::ql = BS::search(i) + 1;                SegmentTree::qr = id-1;                SegmentTree::_max = 0;                SegmentTree::query(1,1,n);                mx = max(mx, SegmentTree::_max);                if (!vis[i+1] && i < n){                    mx = max(mx, a[i+1]);                    //把a[i+1]放到i位置                    if (mx == a[i+1]){                        ans[_i] = a[i+1];                        flg[a[i+1]] = 1;                        SegmentTree::ul = i+1;                        SegmentTree::ur = i+1;                        SegmentTree::v = 0;                        SegmentTree::update(1,1,n);                        continue;                    }                }                //把vidx[mx]放到i                int l = min(vidx[mx], i),r = max(vidx[mx], i);                link(l, r);                for(int j = l; j <= r; j++){                    vis[j] = 1;                    flg[a[j]] = 1;                }                BS::add(l, r);                SegmentTree::ul = l;                SegmentTree::ur = r;                SegmentTree::v = 0;                SegmentTree::update(1,1,n);            }            for(int i=1; i <= n; i++){                printf("%d%c", ans[i], i<n?' ':'\n');            }        }        return 0;    }



0 0
原创粉丝点击