题目大意:
https://codeforces.com/gym/102012/problem/H?csrf_token=c9d0191a64a241166d54a565b1615125
区间[l , r] 中有n条线 问用k种颜色最多能染多少区间 并输出区间和r - l;
∑n <= 2e6,1 <= k <= 2e5,0 <= l < r <= 1e9。
解题思路:
把N*2 个端点排序, 对端点和颜色进行入队出队操作 当颜色为空时说明这个区间满足要求,并将此线段保留到延迟染色的队伍中等待下次染色
ac代码:
#include<bits/stdc++.h> #define sz(x) ((int)x.size()) //#define mp(x, y) make_pair(x, y) using namespace std; typedef long long ll; typedef pair<int, int> pii; const int MAXN = 400010; int T, n, k, col[MAXN]; struct Node{ int st, id; Node(){} Node(int _st, int _id){//方便结构体赋值 st = _st; id = _id; } bool operator < (const Node &nd) const{//否则多定义一个cmd排序 if(st == nd.st) return id < nd.id; return st < nd.st; } }seg[MAXN]; queue<int> rCol, rSeg; int main(){ scanf("%d", &T); while(T --){ scanf("%d%d", &n, &k); while(sz(rCol)) rCol.pop(); while(sz(rSeg)) rSeg.pop(); for(int i = 1; i <= n; i ++){ int l, r; scanf("%d%d", &l, &r); col[i] = 0; seg[i] = Node(l, i); seg[i + n] = Node(r, -i); } if(n < k){ printf("0\n1"); for(int i = 2; i <= n; i ++) printf(" 1"); printf("\n"); continue; } sort(seg + 1, seg + 2*n + 1); for(int i = 1; i <= k; i ++) rCol.push(i); ll ans = 0; for(int i = 1; i <= 2*n; i ++){ if(sz(rCol) == 0)//没有颜色可染,此端点到前个端点必满足条件 ans += seg[i].st - seg[i - 1].st; if(seg[i].id > 0){//左端点进来 if(sz(rCol)){//有颜色染色 ,没颜色放入延迟染色 int tc = rCol.front(); col[seg[i].id] = tc; rCol.pop(); } else rSeg.push(seg[i].id); } else{//右端点出去 if(col[- seg[i].id])//已经染色则归还颜色 rCol.push(col[- seg[i].id]); else//没有说明不做贡献 col[- seg[i].id] = 1; } while(sz(rCol) && sz(rSeg)){ int tc = rCol.front(); int ts = rSeg.front(); rSeg.pop(); if(col[ts]) continue;//归还了颜色没有出队 col[ts] = tc; rCol.pop(); } } printf("%I64d\n", ans); for(int i = 1; i <= n; i ++) printf("%d%c", col[i], i == n ? '\n' : ' '); } return 0; }