题解:CF1732D2 Balance (Hard version)

· · 题解

思路

为了方便,我们提前离散化。

--- 我们先考虑没有删除操作的。 我们用 $S$ 集合记录当且存在的数。 - **加入:** 把数加进 $S$ 里。 - **查询:** 暴力跳,但是我们记忆化一下。具体地,用一个 $tag_i$ 记录这个数跳到的位置,也就是答案为 $tag_i\times x$($x$ 为查询的数)。 ::::info[关于时间复杂度] 这样我们加入时间复杂度为 $O(\log n)$。 对于一个加入集合的数 $x$,发现 $x$ 最多影响**查询值**为**它的约数**的查询,一个数约数的个数为 $O(\log n)$ 的。因为我们做了记忆化,插入的数个数为 $O(n)$,所以总共跳的个数为 $O(n\log n)$。用 set 维护,时间复杂度为 $O(n\log^2 n)$。 :::: --- 现在有一个删除操作,意味着我们暴力跳到答案在前面输出了,但可能在后面删掉了一个更小的数,再来一次查询,答案就不是我们跳到值了(你也不可能再从 $1$ 重新跳)。 所以我们要用另一东西维护那些因**删除**产生的答案。 具体的用 $vec_x$ 维护询问 $x$ 时,那些影响查询 $x$ 的答案且被删除的数。 :::info[辅助理解] 已经加入了 $\{1,2,3,4,5\}$。 现在查询 $1$,那么正常的话,$tag_1$ 会跳到 $6$,答案也为 $6$。 然后我们删除 $3$,那么就将 $3$ 加入进 $vec_1$ 里。 再查询一遍 $1$ 时,就先找 $vec_1$ 里的最小值(找到是 $3$,答案就是 $3$),如果没有值再跳 $tag_1$。 ::: 删掉后再次加入要把 $x$ 所影响的 $vec$ 中的自己删掉。 所以要用 $ye_x$ 和 $re_x$ 辅助维护: * $ye_x$ 表示 $x$ 有没有被删过。 * $re_x$ 表示如果 $x$ 删掉所影响的查询。 所以最终操作为: - **加入:** 加入 $S$,如果删过就把它影响的询问的 $vec$ 中的自己删掉。 - **查询:** 如果 $vec$ 有值,答案就为 $vec$ 的最小值,否则 $tag$ 就暴力跳同时维护 $re_x$。 - **删除:** 给目前 $x$ 删掉会影响的值的 $vec$ 里加入这个 $x$,$S$ 删掉 $x$,更小 $ye_x$。 ::::info[关于时间复杂度] 这里讨论是**加入**和**删除**,其他的前面的**关于时间复杂度**讨论了。 加入需要枚举 $re_x$ 的元素,个数是约数个数 $O(\log n)$,$vec$ 用 set 维护,时间复杂度为 $O(\log^2 n)$。 删除同理,就不赘述了。 :::: # 代码 有需要的可以结合代码理解。 ```cpp #include<bits/stdc++.h> #define fi first #define se second typedef long long ll; using namespace std; const int N=2e5+100; int n; char op[N]; ll a[N]; map<ll,int> mp; ll f[N],tag[N]; bool ye[N]; vector<int> re[N]; set<ll> st,vec[N];//st 即 S void lsh(){ int tot=0; for(auto &it:mp) it.se=++tot,f[tot]=it.fi; for(int i=1;i<=n;i++) a[i]=mp[a[i]]; } int main(){ ios::sync_with_stdio(0); cin.tie(0); cout.tie(0); cin>>n; for(int i=1;i<=n;i++){ cin>>op[i]>>a[i]; mp[a[i]]; } lsh(); //拼音意思,离散化。 for(int i=1;i<=n;i++){ if(op[i]=='+'){ st.insert(f[a[i]]); if(ye[a[i]]){ for(int &it:re[a[i]]) vec[it].erase(f[a[i]]); } } if(op[i]=='-'){ st.erase(f[a[i]]); for(int &it:re[a[i]]) vec[it].insert(f[a[i]]); ye[a[i]]=true; } if(op[i]=='?'){ if(vec[a[i]].size()){ cout<<*vec[a[i]].begin()<<"\n"; }else{ tag[a[i]]=max(tag[a[i]],1ll); set<ll>::iterator it; while((it=st.find(tag[a[i]]*f[a[i]]))!=st.end()){ re[mp[*it]].push_back(a[i]); tag[a[i]]++; } cout<<tag[a[i]]*f[a[i]]<<"\n"; } } } return 0; } ```