【洛谷6105】[Ynoi2010] y-fast trie(set)
大致题意: 给定一个集合\(S\),支持两种操作:加入一个数、删除一个数。每次操作后输出\(\max_{i\in S,j\in S,i\not=j}((i+j)\%C)\)。(强制在线)
分类
首先,第一步显然是对于读入的每个\(x\)将它向\(C\)取模,保证\(0\le x<C\)。
要注意一点,原题中保证没有重复元素,但在我们这么一处理之后就可能会重复,我一开始就因为这个原因挂了。
既然已经满足\(0\le x<C\)了,则\((i+j)\%C\)无非有两种可能:
- \((i+j)\%C=i+j-C\):显然求出当前的最大值和次大值作为\(i,j\)即可。
- \((i+j)\%C=i+j\),这个比较麻烦,是我们接下来着重讨论的。
最优匹配
我们定义\(i\)的最优匹配为\(\max_{j\in S,i+j<C}j\)。
不难发现,必然存在至少一对数满足它们互为最优匹配,且最优解必然是某一对互为最优匹配的数。
对于每一对互为最优匹配的\(i,j\),我们可以把\(i+j\)扔入一个\(set\)中存储。(注意,这里的\(set\)指\(multiset\),为了叙述方便,简称为\(set\))
加入一个数\(x\),我们需要找到它的最优匹配\(y\),接着找到\(y\)原先的最优匹配\(z\)。
如果\(x\le z\),那么\(y\)的最优匹配显然还是\(z\),不予操作。
否则,如果\(z\)的最优匹配是\(y\),那么我们需要在\(set\)中删去\(y+z\)。
然后,由于\(x,y\)互为最优匹配,我们再把\(x+y\)扔入\(set\)中。
删除一个数\(x\),也是类似地找出最优匹配\(y\)和删去\(x\)后\(y\)的最优匹配\(z\)。
如果\(x\le z\),说明\(y\)的最优匹配原本就是\(z\),删除\(x\)没有任何影响,不予操作。
否则,如果\(z\)的最优匹配是\(y\),那么我们需要在\(set\)中加入\(y+z\)。
然后,由于\(x,y\)原本互为最优匹配,删去\(x\)之后这对最优匹配就不存在了,因此在\(set\)中删去。
还有一个遗留问题,如何找到一个数的最优匹配?
我们只要另开一个\(multiset\),存下所有的元素,然后只要求最大的小于等于\(C-x-1\)就可以了。
代码
#include<bits/stdc++.h>
#define Tp template<typename Ty>
#define Ts template<typename Ty,typename... Ar>
#define Reg register
#define RI Reg int
#define Con const
#define CI Con int&
#define I inline
#define W while
#define N 500000
using namespace std;
int tot,X;multiset<int> V,S;multiset<int>::iterator it;
class FastIO
{
private:
#define FS 100000
#define tc() (A==B&&(B=(A=FI)+fread(FI,1,FS,stdin),A==B)?EOF:*A++)
#define pc(c) (C==E&&(clear(),0),*C++=c)
#define D isdigit(c=tc())
int T;char c,*A,*B,*C,*E,FI[FS],FO[FS],S[FS];
public:
I FastIO() {A=B=FI,C=FO,E=FO+FS;}
Tp I void read(Ty& x) {x=0;W(!D);W(x=(x<<3)+(x<<1)+(c&15),D);}
Tp I void writeln(Ty x) {W(S[++T]=x%10+48,x/=10);W(T) pc(S[T--]);pc('\n');}
I void IEE() {pc('E'),pc('E'),pc('\n');}
I void clear() {fwrite(FO,1,C-FO,stdout),C=FO;}
}F;
I int Match(CI x,bool f)//求最优匹配,f表示是否要除去x自身
{
if(!~x) return -1;if((it=V.upper_bound(X-x-1))==V.begin()) return -1;//找不到返回-1
if(--it,f&&*it==x&&V.count(x)==1) return it==V.begin()?-1:*--it;return *it;//特判等于自身的情况
}
I void Ins(CI x)//插入
{
RI y,z;if(tot==1) goto End;y=Match(x,0),z=Match(y,1);
~y&&x>=z&&(~z&&y==Match(z,1)&&(S.erase(S.find(y+z)),0),S.insert(x+y),0);End:V.insert(x);
}
I void Del(CI x)//删除
{
if(V.erase(V.find(x)),!tot) return;RI y=Match(x,0),z=Match(y,1);
~y&&x>=z&&(~z&&y==Match(z,1)&&(S.insert(y+z),0),S.erase(S.find(x+y)),0);
}
I int QV() {return V.count(*(it=--V.end()))>1?(*it<<1)%X:(*it+*--it)%X;}//(i+j)%C=i+j-C
I int QS() {return S.empty()?-1:*--S.end();}//(i+j)%C=i+j
int main()
{
RI Qt,op,x,lst=0;F.read(Qt),F.read(X);W(Qt--)
F.read(op),F.read(x),x^=lst,op==1?(++tot,Ins(x%X)):(--tot,Del(x%X)),//tot记录元素个数
tot<2?(lst=0,F.IEE()):F.writeln(lst=max(QV(),QS()));//tot<2输出EE,否则询问
return F.clear(),0;
}