HDU 6301 Distinct Values【线段树||优先队列】

题意:给你一个区间 [ 1 , n ] ,m个询问,每次询问 [ l , r ] ,表示这段区间数字不相重,输出字典序最小的排列.
分析:
区间与区间的关系有三种:包含,相交,分离;
把包含区间段的可以去掉,只剩下两种。先按照左端排下序,用线段树维护填第i个位置的最小值,查询 O ( 1 ) ,区间单点更新 O ( n l g n ) .

#include <cstdio> 
#include <algorithm>
#include <cstring>
#include <cmath>
using namespace std;

typedef long long LL;
const int MAXN = 1e5 + 10;
int dp[MAXN << 2], cnt[MAXN];

struct node {
    int L, R;
}s[MAXN], ss[MAXN];

void pushup(int root) {
    dp[root] = min(dp[root << 1], dp[root << 1 | 1]);
}

void build(int root, int L, int R) {
    if(L == R) {
        dp[root] = L;
        return ;
    }
    int mid = (L + R) >> 1;
    build(root << 1, L, mid);
    build(root << 1 | 1, mid + 1, R);
    pushup(root);
}

void updata(int root, int L, int R, int x, int flag) {
    if(L == R) {
        if(flag) dp[root] = L;
        else dp[root] = 1e8;
        return ;
    }
    int mid = (L + R) >> 1;
    if(x <= mid) updata(root << 1, L, mid, x, flag);
    else updata(root << 1 | 1, mid + 1, R, x, flag);
    pushup(root);
}

bool cmp(node x, node y) {
    if(x.L != y.L) return x.L < y.L;
    return x.R > y.R;
}

int main() {
    int T, n, m;
    while(scanf("%d", &T) != EOF) {
        while(T--) {
            memset(cnt, 0, sizeof(cnt));
            scanf("%d %d", &n, &m);
            build(1, 1, n);
            for(int i = 0; i < m; ++i) {
                scanf("%d %d", &ss[i].L, &ss[i].R);
            }
            sort(ss, ss + m, cmp);
            int p = 1, ans = ss[0].R;
            s[0].L = ss[0].L, s[0].R = ss[0].R;
            for(int i = 1; i < m; ++i) {
                if(ans >= ss[i].R) continue;
                ans = ss[i].R;
                s[p].L = ss[i].L, s[p++].R = ss[i].R;
            }
            int res = s[0].L;
            for(int i = 0; i < p; ++i) {
                res = max(s[i].L, res);
                for(int j = res; j <= s[i].R; ++j) {
                    cnt[j] = dp[1];
                    updata(1, 1, n, cnt[j], 0);
                }
                res = s[i].R + 1;
                if(i == p - 1) continue;
                int len = min(res, s[i + 1].L);
                for(int j = s[i].L; j < len; ++j) {
                    updata(1, 1, n, cnt[j], 1);
                }
            }
            for(int i = 1; i < n; ++i) {
                if(!cnt[i]) printf("%d ", 1);
                else printf("%d ", cnt[i]);
            }
            printf("%d\n", cnt[n] ? cnt[n] : 1);
        }
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_36368339/article/details/81187472