把博客园图标替换成自己的图标
把博客园图标替换成自己的图标end

【洛谷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;
}
posted @ 2020-07-22 08:50  TheLostWeak  阅读(322)  评论(0编辑  收藏  举报