洛谷 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^5,1\leq C\leq 1073741823,0\leq x\leq 1073741823。
被stl送走了= =
首先肯定要把 x 对 C 取模,然后这样集合里最大的两个数的和的范围就变成了 [0,2C) ,然后讨论一下最大值的情况。
如果 C \le i+j < 2C ,那就肯定是选最大值和次大值了。
如果 0\le i+j < C ,那就需要对每个数 i 找出最大的一个和他相加 <C 的数 j ,这里我们简称 j 为 i 的匹配。
但是如果每次加入一个数都更新匹配复杂度显然是不对的,所以我们考虑优化。
假如加入一个数 a ,他的匹配是 b ,然后我们找到 b 的双向匹配 c( b 是 c 的匹配,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;
}
【推荐】还在用 ECharts 开发大屏?试试这款永久免费的开源 BI 工具!
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 从问题排查到源码分析:ActiveMQ消费端频繁日志刷屏的秘密
· 一次Java后端服务间歇性响应慢的问题排查记录
· dotnet 源代码生成器分析器入门
· ASP.NET Core 模型验证消息的本地化新姿势
· 对象命名为何需要避免'-er'和'-or'后缀
· “你见过凌晨四点的洛杉矶吗?”--《我们为什么要睡觉》
· 编程神器Trae:当我用上后,才知道自己的创造力被低估了多少
· C# 从零开始使用Layui.Wpf库开发WPF客户端
· C#/.NET/.NET Core技术前沿周刊 | 第 31 期(2025年3.17-3.23)
· 接口重试的7种常用方案!