Codeforces915E Physical Education Lessons

本文介绍了一种使用ODT思想解决大规模染色问题的方法。通过对区间进行合并与拆分,有效地处理了大量黑色石子的染色操作,同时维护了黑色石子的数量。采用set和pair实现高效的操作。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目:

现有n个黑色石子。每次将(l,r)内的石子染成黑色或白色。每次染色后输出当前有多少个黑色石子。
(1 ≤ n ≤ 1e9, 1 ≤ q ≤ 3·1e5)

分析:

这道题也是用ODT的思想,合并和拆开区间。

分析可得:虽然n非常大。但一开始只有一个三元组,每次操作最多增加两个三元组,每个三元组最多删除一次。所以set中元素不会特别多。而黑色石子的和可以随着操作一起维护。

用set来维护黑色石子的区间,一开始是(1,n)。因为set中不包括白色石子的区间,所以set中的区间不一定连续,需要修改一下split函数,使得其能正确返回想要的区间。

split(int pos)的功能是:返回一个区间(L,R),其中 L 要大于等于 pos。

这样假如我们要把(l,r)涂成白色,就在set中找到包含在(l,r)这段区间内的黑色区间,然后把他们全部删除,维护sum即可。如果是涂成黑色,同样先全部删除,然后再添加进一个(L,R)即可。

通过这道题发现,pair的速度比struct快很多很多。

代码:

#include <bits/stdc++.h>
using namespace std;
#define ms(a,b) memset(a,b,sizeof(a))
#define lson rt*2,l,(l+r)/2
#define rson rt*2+1,(l+r)/2+1,r
typedef unsigned long long ull;
typedef long long ll;
const int MAXN = 105;
const double EPS = 1e-8;
const int INF = 0x3f3f3f3f;
typedef pair<int,int> P;

set<P> s;
int n, m, sum;

set<P>::iterator split(int pos) {
    if(s.empty())   return s.end();
    auto it = s.lower_bound(make_pair(pos,0));
    if(it != s.end() && it->first == pos)   return it;
    if(it == s.begin()) return it;
    auto last = --it;   ++it;
    if (it!=s.end() && it->first > pos && last->second < pos)   return it;
    --it;
    if (pos > it->second)   return  s.end();
    int L = it->first, R = it->second;
    s.erase(it);
    s.insert(make_pair(L, pos - 1));
    return s.insert(make_pair(pos, R)).first;
}


int main() {
    ios::sync_with_stdio(false);
    cin >> n >> m;
    sum = n;
    s.insert(make_pair(1,n));
    for (int i = 1; i <= m; i++) {
        int l,r,k;
        cin >> l >> r >> k;
        split(l);
        auto itr = split(r + 1), itl = split(l);
        while(itl != itr){
            auto tmp = itl;
            sum -= (tmp->second-tmp->first+1);
            itl++;
            s.erase(tmp);
        }
        if(k==2){
            s.insert(make_pair(l,r));
            sum += (r-l+1);
        }

        cout << sum << endl; 
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值