杭电2018暑假多校第一场 D Distinct Values hdu6301 贪心

Distinct Values

Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 1411    Accepted Submission(s): 439


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 (li<jr), aiajholds.
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 (1n,m105) -- the length of the array and the number of facts. Each of the next m lines contains two integers li and ri (1lirin).

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
 

 

Source
 
题意:题目要求的是构造一个数组在区间内各点的值不相同,且构造的数组字典序要最小

分析:由题意可以得到,终点相同的区间他们的起点可以简化成几个区间内最小的起点

而要使值都不相同,我们首先要知道的是每个点的起始点,然后看这个点的区间内已经填了哪些值,我们再填除了这些值外最小的点,每个点的起始点就是其所在区间的起始点

求出每个点的起始点后,我们只需要用个值记录下这个区间前面的点出现过的值

在这里我们用set存每出现过的值,首先把所有可能的值加入set(用set的好处是他自己排序,第一个为最小的),然后在第一个区间一个个依次加入,每加入一个我们删去一个

接下来的区间用记录的值与区间的起始点比较,如果小于点的起始点的值,证明前面的点没出现过再加入我们的集合,然后取set的第一个值就行了

#include <map>
#include <set>
#include <stack>
#include <cmath>
#include <queue>
#include <cstdio>
#include <vector>
#include <string>
#include <cstring>
#include <iomanip>
#include <iostream>
#include <algorithm>
#define debug(a) cout << #a << " " << a << endl
using namespace std;
const int maxn = 1e5+10;
const int mod = 1e9 + 7;
typedef long long ll;
ll pre[maxn], ret[maxn];
int main() {
    std::ios::sync_with_stdio(false);
    ll T, n, m;
    cin >> T;
    while( T -- ) {
        cin >> n >> m;
        for( ll i = 1; i <= n; i ++ ) {
            pre[i] = i;
        }
        for( ll i = 0, le, ri; i < m; i ++ ) {
            cin >> le >> ri;
            pre[ri] = min( pre[ri], le );   //相同终点的区间起点取小的
        }
        for( ll i = n-1; i >= 1; i -- ) {
            pre[i] = min( pre[i], pre[i+1] );//将处在区间内的点的起点定义为区间的起点
            //debug(pre[i]);
        }
        ll p1 = 1;  //代表数字用到哪一个点的,前面填充好,后面通过p1对应到前面的点
        set<ll> s;
        for( ll i = 1; i <= n; i ++ ) {
            s.insert(i);
        }
        for( ll i = 1; i <= n; i ++ ) {
            //debug(i);
            while( p1 < pre[i] ) {  //p1根据区间不同不断更新,当小于i点的区间起点时p1进行更新
                s.insert(ret[p1]);
                // debug(ret[p1]);
                p1 ++;
            }
            ret[i] = *s.begin();
            debug(ret[i]);
            s.erase(ret[i]);
        }
        for( ll i = 1; i <= n; i ++ ) {
            if( i != n ) {
                cout << ret[i] << " ";
            } else {
                cout << ret[i] << endl;
            }
        }
    }
    return 0;
}

  

转载于:https://www.cnblogs.com/l609929321/p/9358636.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值