zoukankan      html  css  js  c++  java
  • HDU-6301 Distinct Values(区间平移构造数组)

    Problem Description
    Chiaki has an array of n positive integers. You are told some facts about the array: for every two elements ai and aj in the subarray al..r (l ≤ i < j ≤ r), ai≠aj holds.
    Chiaki would like to find a lexicographically minimal array which meets the facts.

    Input
    There are multiple test cases. The first line of input contains an integer T, indicating the number of test cases. For each test case:

    The first line contains two integers n and m (1≤n,m≤105) – the length of the array and the number of facts. Each of the next m lines contains two integers li and ri (1≤ li ≤ r i≤ n).

    It is guaranteed that neither the sum of all n nor the sum of all m exceeds 106.

    Output
    For each test case, output n integers denoting the lexicographically minimal array. Integers should be separated by a single space, and no extra spaces are allowed at the end of lines.

    Sample Input
    3
    2 1
    1 2
    4 2
    1 2
    3 4
    5 2
    1 3
    2 4

    Sample Output
    1 2
    1 2 1 2
    1 2 3 1 1

    题意:输入测试次数T,给出要生成序列的长度N,给出限定的M个区间,每个区间输入L,R表示区间边界,保证区间内没有任何一个重复的数,构造一个序列满足上述条件并使其字典序最小。

    思路:首先字典序最小想到的即是一直将较小的数排到前面,而保证每个区间内不能有重复的数即涉及在某一个区间内相同的数字只能使用一次,在大区间覆盖的小区间上,可以很容易想到因为大区间在构造时就保证了每个数唯一,那么小区间的构造可以直接背忽略。而两个或多个交叉区间是比较难处理的,对于一个区间使用了几个较小数填充,而下一个区间中,因为与上一个区间重叠,重叠部分中的数是不能在重叠部分之外再次使用的,这样会导致其中一个区间粗线重复数,又要保证字典序最小,也就是尽量不要用更大的数,那么我们就把上一个区间中不与当前区间重叠的部分直接平移到下一个区间的不重叠部分,这样保证了数字不重复且最大利用较小数字。

    这样就产生了一个释放被使用数字,和使用数字的概念。对于一个区间,采用L指针和R指针表示区间两边,当一个区间构造完成后,我们先移动L指针,使得左边不重叠部分的数先被释放,这些被释放的数投入到优先队列中,保证下次使用这些可以使用的数字时保证用到的顺序都是最小的。然后移动R指针,使得R指针移动到下一个区间的右边界。移动的过程中,可以直接利用之前释放的数构造下一个区间的不重叠部分。也就是将数字从优先队列中弹出。

    有一点问题是,如果我们一开始就将N个可能被使用的数字投入到优先队列中候选,很明显复杂度很高,太蠢会超时。此时记录一个当前使用的最大值,相当于一个袋子,里面我一开始有第一个区间需要用的数,用完了就再塞回袋子,给另一个区间继续用,当袋子中的数不够用时,我们做一个标记MAXNUM++,表示数字不够了,应该增大最大数字的提供,这样在需要用到较多的数时再申请,就不会出现多余的浪费,使得一些从来都没被使用的数也插入到袋子里。

    #include<bits/stdc++.h>
    using namespace std;
    const int maxn=1e5+10;
    int t,n,m,a[maxn];
    struct node
    {
        int l,r;
    } qu[maxn];
    bool cmp(node a,node b)///按左边界较小排序,这样符合遍历顺序,按右边界较大排序,这样遍历到的区间都较大,不会遍历到无效(被大区间完全覆盖的)区间
    {
        if(a.l==b.l)return a.r>b.r;
        return a.l<b.l;
    }
    priority_queue<int,vector<int>,greater<int> >q;
    int ans[maxn];
    int main()
    {
        scanf("%d",&t);
        while(t--)
        {
            scanf("%d%d",&n,&m);
            memset(ans,0,sizeof ans);
            for(int i=0; i<m; i++)scanf("%d%d",&qu[i].l,&qu[i].r);
            sort(qu,qu+m,cmp);
            while(!q.empty())q.pop();
            int maxnum=1,pl=qu[0].l,pr=qu[0].r;
            if(m!=0)
            {
                for(int i=qu[0].l; i<=qu[0].r; i++)ans[i]=maxnum++;
                for(int i=1; i<m; i++)
                {
                    while(pl<qu[i].l)
                    {
                        if(pl<=pr)q.push(ans[pl]);///只有当L指针小于R指针时才将被释放的数字投入队列中
                        pl++;
                    }
                    while(pr<qu[i].r)
                    {
                        pr++;
                        if(!q.empty())
                        {
                            if(pr>=pl)ans[pr]=q.top(),q.pop();///同理只有当R指针大于L指针时才赋值数组
                        }
                        else ans[pr]=maxnum++;///如果队列为空,说明被使用的最大值变大,那么此时才将优先队列中候选值的数量增加
                    }
                }
            }
            for(int i=1; i<=n; i++)printf("%d%c",ans[i]==0?1:ans[i],i==n?'
    ':' ');
        }
    }
    /*
    99
    2 1
    1 2
    4 2
    1 2
    3 4
    5 2
    1 3
    2 4
    9 0
    9 2
    1 3
    5 7
    */
    
  • 相关阅读:
    清除浮动的方式
    网页在线测试工具
    仿京东左侧菜单 hover效果-简易demo
    原生js,插入元素
    知识补漏
    css3动画
    java微信开发(wechat4j)——支持微信JS-SDK的jsapi_ticket中控服务器
    java微信开发(wechat4j)——access_token中控服务器实现
    java微信开发(wechat4j)——wechat4j配置文件解读
    java微信开发(wechat4j)——设置响应微信参数
  • 原文地址:https://www.cnblogs.com/kuronekonano/p/11135725.html
Copyright © 2011-2022 走看看