*题解:P6105 [Ynoi2010] y-fast trie
解析
容易发现所有元素对 \(C\) 取模不影响答案,所以取模后进行分类讨论。
取模后对于集合内任意两元素 \(x,y\),有 \(x + y < 2C\),若 \(x + y \ge C\),则 \((x + y) \bmod C=x+y-C\),此时我们显然希望 \(x,y\) 尽可能大,所以取最大值和次大值。
否则,在 \(x\) 确定的情况下我们希望找到使得 \(x + y < C\) 的最大 \(y\)。考虑将这样的 \(x,y\) 配对并将贡献存到一个 multiset 里,但是这样的话在修改时会影响 \(O(|S|)\) 个位置。不能维护所有的配对,那应该维护什么样的配对呢?对于最优配对 \((x,y)\),必定有 \((y,x)\) 与之对应,否则会出现更优秀的配对,能不能只维护这些双向配对的贡献呢?
考虑插入,我们需要判断新加入的元素 \(x\) 能否创造一个双向配对。先找到 \(x\) 的配对 \(y\),再找到 \(y\) 的配对 \(z\), \((x,y)\) 比 \((y,z)\) 更优当且仅当 \(x > z\),所以如果 \(x > z\),就可以建立 \(x\) 与 \(y\) 的双向链接,同时如果 \(y\) 与 \(z\) 已经建立了双向链接,则需要切断。
考虑删除,我们需要判断将要删除的元素 \(x\) 是否建立了双向配对,如果是则需要让配对的元素 \(y\) 重新寻找配对,类似插入的过程。
时间复杂度 \(O(n\log n)\)。
代码
#include <bits/stdc++.h>
#define ls(p) ((p) << 1)
#define rs(p) (((p) << 1) | 1)
#define mid ((l + r) >> 1)
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
const int N = 600 + 5,M = 5e5,mod = 998244353;
int n,c;
multiset<int> s,res;
map<int,int> cnt;
map<pair<int,int>,int> m;
int find(int x,bool f){//f 表示 x 是否在集合内
if(x == -1) return -1;
auto it = s.upper_bound(c - 1 - x);
if(it == s.begin()) return -1;
it--;
if(*it == x && cnt[x] == 1 && f){
if(it == s.begin()) return -1;
it--;
}
return *it;
}
void insert(int x){
int y = find(x,0),z = find(y,1);
if(y != -1 && z <= x){
if(m[{min(y,z),max(y,z)}]){
res.erase(res.find(y + z));
m[{min(y,z),max(y,z)}] = false;
}
m[{min(y,x),max(y,x)}] = true;
res.insert(x + y);
}
s.insert(x);
cnt[x]++;
}
void erase(int x){
int y = find(x,1),z = find(y,1);
s.erase(s.find(x));
cnt[x]--;
if(z == x){
if(m[{min(y,x),max(y,x)}]){
res.erase(res.find(x + y));
m[{min(y,x),max(y,x)}] = false;
}
z = find(y,1);
int k = find(z,1);
if(z != -1 && k <= y){
res.insert(z + y);
m[{min(y,z),max(y,z)}] = true;
}
}
}
int ask(){
if(s.size() < 2){
return -1;
}
int ans = max(*s.rbegin() + *next(s.rbegin()) - c,res.size() == 0 ? 0 : *res.rbegin());
return ans;
}
int main(){
ios::sync_with_stdio(false);
cin.tie(0);
// freopen("in.txt","r",stdin);
// freopen("out.txt","w",stdout);
cin>>n>>c;
int l = 0;
while(n--){
int op,x;
cin>>op>>x;
x ^= l;
x %= c;
if(op == 1){
insert(x);
}else{
erase(x);
}
int ans = ask();
if(ans == -1){
l = 0;
cout<<"EE\n";
}else{
l = ans;
cout<<ans<<'\n';
}
}
return 0;
}

浙公网安备 33010602011771号