【题解】[Ynoi2010] y-fast trie
题目分析:
显然可以对于所有的 对 取模后处理。
那么就是两种情况:
对于第一种情况直接找最大的两个数就好了,关键就是第二种情况。
其实我们可以考虑,维护每一个数的最优匹配是什么。
这样的话插入操作就非常简单了,直接去匹配就好了,但是删除操作如果直接暴力删除的话可能会出现一次删除 个,因为会有连锁反应。
当然,如果这个题不强制在线直接线段树分治就可以实现只有插入操作,但是它偏偏就是强制在线。
我们考虑对于 的最优匹配为 而 的最优匹配为 ,那么 一定是不优于 的,这个应该很显然吧。
那么此时我们就不去维护 了,因为不可能最优,所以就去维护 也就是双向匹配才可能是最优解。
这样的话每次插入和删除都更改 的匹配,复杂度就很对了。
代码加了注释,所以应该会好懂很多。
代码:
点击查看代码
#include <bits/stdc++.h>
using namespace std;
int n,c,sz;
multiset<int> a,b;
multiset<int>::iterator it;
int best(int x,int op){ //找最优值
if(x==-1) return -1;
it=a.upper_bound(c-1-x); //找前驱
if(it==a.begin()) return -1;
it--;
if(op==1 && *it==x && a.count(x)==1) return (it==a.begin())?-1:*--it; //判掉最优值就是这个数的情况
else return *it;
}
void insert(int x){
sz++;
if(sz==1){
a.insert(x);
return;
}
int y=best(x,0),z=best(y,1),w=best(z,1);
if(y!=-1 && z<x){ //注意,此时找到的都是没有插入 x 的时候的值
if(z!=-1 && y==w) b.erase(b.find(y+z));
b.insert(x+y);
}
a.insert(x);
}
void erase(int x){
a.erase(a.find(x)),sz--;
if(!sz) return;
int y=best(x,0),z=best(y,1),w=best(z,1);
if(y!=-1 && z<x){ //注意,此时找到的都是删除 x 的时候的值
if(z!=-1 && y==w) b.insert(y+z);
b.erase(b.find(x+y));
}
}
inline int query(){
it=--a.end();
return (*it+*--it)%c;
}
int main(){
scanf("%d%d",&n,&c);
int lst=0;
while(n--){
int op,x;
scanf("%d%d",&op,&x); x^=lst;
if(op==1) insert(x%c);
else erase(x%c);
if(sz<2) puts("EE"),lst=0;
else printf("%d\n",lst=max(query(),b.empty()?0:*--b.end()));
}
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 单元测试从入门到精通
· 上周热点回顾(3.3-3.9)
· winform 绘制太阳,地球,月球 运作规律