[COCI2010-2011#6] STEP

题目链接
题解

  • 这题可以通过线段树的方法较为轻松的解决,而我的这个方法更为暴力。
  • 我们可以考虑维护以下两个操作:
  • m e r g e ( x , y ) merge(x, y) merge(x,y)令这两个位置的集合进行暴力合并
    s p l i t ( x ) split(x) split(x)使得位置 x x x的数从集合中脱离出来
    – 用 m u l t i s e t multiset multiset维护每个区间的长度,用 s e t < p a i r > set<pair> set<pair>来维护每个区间的左右区间
  • 对于 m e r g e ( x , y ) merge(x,y) merge(x,y)这个操作,通过 l o w e r _ b o u n d lower\_bound lower_bound找出包含 x x x y y y的两个区间,从维护长度和区间的集合中删除这两个区间,再添加合并后的区间即可。
  • 对于 s p l i t ( x ) split(x) split(x)这个操作,我们通过 l o w e r _ b o u n d lower\_bound lower_bound找出 x x x所在的区间,并对其进行分类讨论,按照其在区间内部,首部和尾部三种情况进行拆分。
  • 对于 x x x所在的区间 [ L , R ] [L,R] [L,R]
  • L = x L = x L=x,可以将其拆成 [ x , x ] [x,x] [x,x] [ x + 1 , R ] [x+1,R] [x+1,R]两个区间。
  • R = x R = x R=x,可以将其拆成 [ L , x − 1 ] [L,x-1] [L,x1] [ x , x ] [x,x] [x,x]两个区间。
  • 否则,将其拆成 [ L , x − 1 ] , [ x , x ] , [ x + 1 , R ] [L,x-1],[x,x],[x+1,R] [L,x1],[x,x],[x+1,R]三个区间。
  • 在处理完如上操作后,我们可以方便地得出答案,就是储存区间的 s e t set set r b e g i n rbegin rbegin迭代器的值
  • 至此,我们便完成了对这个问题的讨论,就大功告成啦(悲)(大嘘)
#include<bits/stdc++.h>
#define show(x) cerr << #x << " = " << x << endl;
#define IO ios_base::sync_with_stdio(false);cin.tie(0);cout.tie(0);
#pragma GCC optimize(3)
using namespace std;
typedef unsigned long long ull;
const int mod = 1e9 + 7;
const int maxn = 2e5 + 5;

int n, q;
multiset<int> l;
set<pair<int, int>> x;
int a[maxn];

void merge(int i, int j)
{
    if(i == 0 || j == n + 1)
        return ;

    if(i > j)swap(i, j);

    auto it = x.lower_bound({i, 0});
    auto it2 = x.lower_bound({j, 0});

    if(it->second != i)it --;
    if(it2->first != j)it2 --;

    pair<int, int> s1 = *it;
    pair<int, int> s2 = *it2;

    x.insert({s1.first, s2.second});
    x.erase(s1);
    x.erase(s2);
    l.insert(s2.second - s1.first + 1);
    l.erase(l.find(s2.second - s2.first + 1));
    l.erase(l.find(s1.second - s1.first + 1));
}

void split(int i)
{
    auto it = x.lower_bound({i, 0});

    if(i == it->first && i == it->second)
        return ;

    if(i < it->first || i > it->second)
        it --;

    pair<int, int> pr = *it;

    int le = pr.second - pr.first + 1;

    if(pr.first == i || i == 1)
    {
        x.insert({i, i});
        x.insert({i + 1, pr.second});
        x.erase(pr);

        l.insert(1);
        l.insert(le - 1);
        l.erase(l.find(le));

        return ;
    }

    if(pr.second == i || i == n)
    {
        x.insert({i, i});
        x.insert({pr.first, i - 1});
        x.erase(pr);

        l.insert(1);
        l.insert(le - 1);
        l.erase(l.find(le));
        return ;
    }

    int llen = i - pr.first, rlen = pr.second - i;

    x.insert({pr.first, i - 1});
    x.insert({i, i});
    x.insert({i + 1, pr.second});
    x.erase(x.find(pr));
    l.insert(1);
    l.insert(llen);
    l.insert(rlen);
    l.erase(l.find(le));
}

void solve()
{
    cin >> n >> q;

    for(int i = 1; i <= n; i ++)
        l.insert(1);

    for(int i = 1; i <= n; i ++)
        x.insert({i, i});

    for(int i = 1; i <= q; i ++)
    {
        int t;
        cin >> t;
        a[t] ^= 1;

        if(a[t] == a[t - 1] || a[t] == a[t + 1])
            split(t);

        if(a[t] != a[t + 1])
            merge(t, t + 1);

        if(a[t] != a[t - 1])
            merge(t - 1, t);

        cout << *l.rbegin() << '\n';
    }
}

signed main()
{
    IO
    solve();
    return 0;
}
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值