codeforces round #595 D2. Too Many Segments

https://codeforces.com/contest/1249/problem/D2

这道题就是贪心选择最右的一个区间。重点是对区间操作的一些技巧。考试的时候考虑用线段树。其实完全没有必要。

#include<bits/stdc++.h>
using namespace std;
const int N = 2e5+10;

vector<pair<int, int>> segs(N);
int cnt[N]; // 对于一个区间【a, b】每个元素要加一。则cnt[a]++, cnt[b + 1]--。求前缀和之后,【a,b】之间的元素就全为1
vector<vector<int>> envs(N); // envs[i]记录了以i这个点开始和结束的区间的号码。大于0为开始点。小于0为结束点


int main()
{
    int n, k;
    cin >> n >> k;
    for(int i = 1; i <= n; i++) 
    {
        cin >> segs[i].first >> segs[i].second;
        ++cnt[segs[i].first];
        --cnt[segs[i].second + 1];
        envs[segs[i].first].push_back(i);
        envs[segs[i].second + 1].push_back(-i); // 这里要注意区间[a,b]。b+1的时候才说明走出了区间
    }
    for (int i = 0; i + 1 < N; ++i) {
		cnt[i + 1] += cnt[i];
	}
    /*
        sub也很有意思。对一段区间[a,b]减1。在a开始的时候令cursub+1。令sub[b+1]=-1。到了b+1的时候,cursub += sub[b+1].
        就相当于走出这个区间了。
    */
    vector<int> ans(N), sub(N); 
    set<pair<int, int>> cursegs;
    int cursub = 0;
    for(int i = 0; i < N; i++)
    {
        cursub += sub[i];
        // 把包含这个点所有区间都加进来
        for(auto segindex : envs[i])
        {
            if(segindex > 0) cursegs.insert({segs[segindex].second, segindex});
            else
            {
                // 要走出i这个位置了,把i这个位置结尾的全删掉
                auto it = cursegs.find({segs[-segindex].second, -segindex});
                if(it != cursegs.end()) cursegs.erase(it);
            }
        }
        while(cnt[i] - cursub > k)
        {
            assert(!cursegs.empty());
            // 贪心的找出最右的区间
            int rightindex = cursegs.rbegin()->second;
            cursegs.erase(prev(cursegs.end()));
            sub[segs[rightindex].second + 1]--;
            cursub++;
            ans[rightindex] = 1;
        }
    }
    cout << accumulate(ans.begin(), ans.end(), 0) << endl;
    for(int i = 1; i <= n; i++)
        if(ans[i]) cout << i << " ";
    cout << endl;
    return 0;
}
发布了44 篇原创文章 · 获赞 0 · 访问量 965

猜你喜欢

转载自blog.csdn.net/weixin_37748689/article/details/102701182