题解 P6105 【[Ynoi2010]y-fast trie】

· · 题解

按照传统先取模,然后分类讨论:

$2.$ $0 \leq (i + j) \leq C - 1$,那么答案在每个 $i$ 最优的 $j$ 取到。 考虑第二种情况。 一个比较 simple 的想法是维护每个 $i$ 的最优匹配 $j$(注意到这是单向的),用 $\text{multiset}$ 维护,但这样删除会被卡到 $O(|S|)$。 对上述做法进行优化,减小可能成为答案的集合。 本题关键在于,如果你要加入/删除一个数 $x1$,其最优匹配为 $x2$ ,需要用这两个数排除掉不优的决策。 这些决策一定至于 $x1,x2$ 相关,设 $x2$ 的最优匹配为 $x3$,若 $x1 > x3$,则 $(x2 , x3)$ 是无用的。 可以证明,保留的匹配个数是 $O(n)$ 级的。 也许会有这样的一个问题,如果删除产生了连锁反应怎么办? 注意到可能的决策集合变化大小始终不超过 $1$ ,而数集是不可重的,也就是说决策集合的元素用到的时候一定对应着数集的变化。 用两个 $\text{multiset}$ 分别维护数集与决策集合,实现有一些细节(注意 $\text{multiset}$ 的 count函数复杂度是错的)。 以下是代码实现,参考了 Owen_codeisking 的代码。 ```cpp #include <set> #include <cstdio> #include <vector> #include <cstring> #include <iostream> #include <algorithm> using namespace std; inline int read() { register char c = getchar(); register int x = 0, f = 1; while(c < '0' || c > '9') { if (c == '-') f = -1; c = getchar(); } while(c >= '0' && c <= '9') { x = (x << 3) + (x << 1) + c - 48; c = getchar(); } return x * f; } using namespace std; int n , C; multiset <int> s1 , s2; // s1 : num , s2 : pair multiset <int> ::iterator it; inline int get_pair(int x , int o) { if(x == -1) return -1; it = s1.upper_bound(C - x - 1); if(it == s1.begin()) return -1; --it; if(o == 1 && *it == x && s1.count(x) == 1) { if(it == s1.begin()) return -1; return *--it; } else return *it; } int cnt = 0; inline void insert(int x1) { cnt++; if(cnt == 1) { s1.insert(x1); return; } int x2 = get_pair(x1 , 0); int x3 = get_pair(x2 , 1); int x4 = get_pair(x3 , 1); if(x2 != -1 && x1 > x3) { if(x3 != -1 && x2 == x4) s2.erase(s2.find(x2 + x3)); s2.insert(x1 + x2); } s1.insert(x1); } inline void erase(int x1) { cnt--; s1.erase(s1.find(x1)); if(!cnt) return;int x2 = get_pair(x1 , 0); int x3 = get_pair(x2 , 1); int x4 = get_pair(x3 , 1); if(x2 != -1 && x1 > x3) { if(x3 != -1 && x2 == x4) s2.insert(x2 + x3); s2.erase(s2.find(x1 + x2)); } } inline int query(){ it = --s1.end(); int num = *it; s1.erase(it); if(s1.find(num) != s1.end()){ s1.insert(num); return num * 2 % C; } // if(s1.count(*it) >= 2) // return *it * 2 % C; else{ s1.insert(num); it = --s1.end(); return (*it + *--it) % C; } } int main() { n = read() , C = read(); int lstans = 0; while(n--) { int opt = read() , x = (read() ^ lstans) % C; if(opt == 1) insert(x); else erase(x); if(cnt < 2){ puts("EE"); lstans = 0; } else{ lstans = max(query() , s2.empty() ? 0 : *--s2.end()); printf("%d\n" , lstans); } } return 0; } ```