P6105 [Ynoi2010] y-fast trie

题解

Posted by WrongAnswer_90's Blog on January 18, 2024

更好的阅读体验

P6105 [Ynoi2010] y-fast trie

首先把所有数对 $C$ 取模,分类讨论:

  1. $x+y\geq C$

因为只会取模一次,这时显然取最大值和次大值。

  1. $x+y<C$

一开始的想法是对于每一个数 $a$ 找到另一个数满足 $a+b<C$ 的最大的 $b$,这样是一棵外向树(环长一定 $=2$),修改如果修改到入度比较大的节点复杂度不对。

接下来是神奇套路:$(a,b)$ 需要被维护当且仅当 $(a,b)$ 互为最优配对。

对于加数,加进去的数 $a$ 寻找一个最优配对 $b$,如果 $b$ 没有被配对直接把 $(a,b)$ 扔进堆里。否则比较 $b$ 的配对 $c$ 和 $a$ 的大小,取较大者和 $b$ 配对,较小者不与任何数配对(一定不会与任何数配对,因为较小数找到的配对数一定是 $b$)。

对于删数,如果 $a$ 没有配对直接删掉,否则把 $(a,b)$ 都删掉,然后插入 $b$。

显然上述操作一定不会遗漏互为最优的配对。

开一个堆维护所有配对,开一个 set 维护所有数,复杂度 $\mathcal O(n\log n)$。注意插入的数中可能有 $0$。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
	struct Node{int v,oth;Node(int V,int Oth){v=V,oth=Oth;};};
	bool operator <(const Node nd1,const Node nd2){return nd1.v<nd2.v||(nd1.v==nd2.v&&nd1.oth<nd2.oth);}
	multiset<Node> st;
	struct Delq
	{
		priority_queue<int> q1,q2;
		inline void ins(int x){q1.e(x);}
		inline void del(int x){q2.e(x);}
		inline void update(){while(q1.size()&&q2.size()&&q1.top()==q2.top())q1.pop(),q2.pop();}
		inline int top(){return update(),q1.size()?q1.top():-inf;}
	}q;
	int n,m;
	inline void ins(int x)
	{
		auto it=st.lower_bound(Node(m-x,-1));int oth=-1;
		if(it!=st.begin())
		{
			--it;Node nd=*it;
			if(nd.oth==-1)st.erase(it),st.insert(Node(oth=nd.v,x)),q.ins(nd.v+x);
			else
			{
				if(nd.oth<x)
				{
					st.erase(it),st.erase(st.find(Node(nd.oth,nd.v)));
					st.insert(Node(nd.oth,-1)),st.insert(Node(nd.v,x));
					q.del(nd.v+nd.oth),q.ins(nd.v+x),oth=nd.v;
				}
			}
		}
		st.insert(Node(x,oth));
	}
	inline void mian()
	{
		read(n,m);int opt,x,ans=0;
		while(n--)
		{
			read(opt,x),x=(x^ans)%m;
			if(opt==1)ins(x);
			else
			{
				auto it=st.lower_bound(Node(x,-1));Node nd=*it;
				if(nd.oth==-1)st.erase(it);
				else q.del(nd.oth+nd.v),st.erase(it),st.erase(st.find(Node(nd.oth,nd.v))),ins(nd.oth);
			}
			ans=q.top();
			if(st.size()>=2)Mmax(ans,((--st.end())->v+(--(--st.end()))->v)%m);
			if(ans<0)puts("EE"),ans=0;else write(ans,'\n');
		}
	}