Loading [MathJax]/jax/element/mml/optable/BasicLatin.js

洛谷 P6105 [Ynoi2010] y-fast trie

给定一个常数 C,你需要维护一个集合 S,支持 n 次操作:

  • 操作1:给出 x,插入一个元素 x,保证之前集合中没有 x 这个元素
  • 操作2:给出 x,删除一个元素 x,保证之前集合中存在 x 这个元素

每次操作结束后,需要输出 max,即从 S 集合中选出两个不同的元素,其的和 \bmod~C 的最大值,如果 S 集合中不足两个元素,则输出 EE

本题强制在线,每次的 x 需要 \operatorname{xor} 上上次答案 ,如果之前没有询问或者输出了 EE,则上次答案为 0

1\leq n \leq 5\times 10^51\leq C\leq 10737418230\leq x\leq 1073741823


被stl送走了= =

首先肯定要把 xC 取模,然后这样集合里最大的两个数的和的范围就变成了 [0,2C) ,然后讨论一下最大值的情况。

如果 C \le i+j < 2C ,那就肯定是选最大值和次大值了。

如果 0\le i+j < C ,那就需要对每个数 i 找出最大的一个和他相加 <C 的数 j ,这里我们简称 ji 的匹配。

但是如果每次加入一个数都更新匹配复杂度显然是不对的,所以我们考虑优化。

假如加入一个数 a ,他的匹配是 b ,然后我们找到 b 的双向匹配 cbc 的匹配,c 也是 b 的匹配),若 a>c ,那么显然 b+c 是没有用的,就可以直接扔掉,这样子的匹配就只有 O(n)个了。

用multiset可以轻松解决这个问题。

Code

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <set>
#include <map>
using namespace std;
multiset <int> a;
multiset <int> b;
map <int,int> mp;
multiset <int>::iterator it;
multiset <int>::iterator itt;
int n,C,ans,sm;
inline int find(int x)
{
    it = a.lower_bound(C - x);
    if (it == a.begin())
        return -1;
    return *(--it);
}
inline int match(int x)
{
    if (x == -1)
        return -1;
    it = a.lower_bound(C - x);
    if (it == a.begin())
        return -1;
    it--;
    if (*it == x)
    {
        if (it == a.begin())
            return -1;
        return *(--it);
    }
    return *it;
}
inline void ins(int x)
{
    int y = find(x),z = match(y),xx = match(z);
    if (y != -1 && x > z)
    {
        if (xx == y && z != -1)
            b.erase(b.find(z + y));
        b.insert(x + y);
    }    
    sm++;
    a.insert(x);
}
inline void del(int x)
{
    sm--;
    a.erase(a.find(x));
    int y = find(x),z = match(y),xx = match(z);
    if (y != -1 && x > z)
    {
        if (xx == y && z != -1)
            b.insert(z + y);
        b.erase(b.find(x + y));
    }
}
inline int read()
{
    int X(0),w(0);char ch(0);
    while (!isdigit(ch)) w |= ch == '-',ch = getchar();
    while (isdigit(ch)) X = (X << 3) + (X << 1) + (ch ^ 48),ch = getchar();
    return w ? -X : X;
}
inline int query()
{
    int ans = 0;
    it = a.end();
    it--;
    ans = *it;
    ans %= C;
    it--;
    ans += *it;
    ans %= C;
    itt = b.end();
    if (itt != b.begin())
    {
        itt--;
        ans = max(ans,*itt);
    }
    return ans;
}
int main()
{
    //freopen("data.in","r",stdin);
    //freopen("a1.out","w",stdout);
    n = read();C = read();
    int opt,x;
    while (n--)
    {
        opt = read();x = read();
        x ^= ans;
        //cout<<opt<<"QAQ"<<x<<endl;
        x %= C;
        if (opt == 1)
            ins(x);
        else
            del(x);
        if (sm < 2)
        {
            ans = 0;
            printf("EE\n");
        }
        else
        {
            ans = query();
            printf("%d\n",ans);
        }
    }
    return 0;
}
posted @   eee_hoho  阅读(158)  评论(0编辑  收藏  举报
编辑推荐:
· 从问题排查到源码分析:ActiveMQ消费端频繁日志刷屏的秘密
· 一次Java后端服务间歇性响应慢的问题排查记录
· dotnet 源代码生成器分析器入门
· ASP.NET Core 模型验证消息的本地化新姿势
· 对象命名为何需要避免'-er'和'-or'后缀
阅读排行:
· “你见过凌晨四点的洛杉矶吗?”--《我们为什么要睡觉》
· 编程神器Trae:当我用上后,才知道自己的创造力被低估了多少
· C# 从零开始使用Layui.Wpf库开发WPF客户端
· C#/.NET/.NET Core技术前沿周刊 | 第 31 期(2025年3.17-3.23)
· 接口重试的7种常用方案!
点击右上角即可分享
微信分享提示