题解:P12446 [COTS 2025] 答好位 / Vrsta

· · 题解

考虑如果需要回答的是最大怎么做。维护一个单调栈,加入一个点的时候询问当前栈顶 j 到新元素 i 这段区间,如果 p_j<p_i 那么次大就应该是 j(因为他原来是最大),遇到第一个 p_j>p_i 次大就变成 i 了,存下每个位置的单调栈就可以用 2n 次询问回答出最大的问题。

然后考虑拓展一下这个单调栈,把所有会更新次大的元素也加入。称更新最大的元素为第一类,更新次大的为第二类。

考虑加入 i 时单调栈怎么变化:设 p 为左侧第一个大于 i 的,p 右侧的第一类元素全部变为第二类,第二类元素全都删掉,然后删除 p 到左边下一个第一类元素之间第二类元素的一个后缀,最后加入第一类元素 i

```cpp cin>>n; vector<pair<int,bool>> stk; stk.emplace_back(1,0); rep(i,2,n){ vector<int> rm; while(!stk.empty()){ if(stk.back().sec){ stk.pop_back(); continue; } if(ask(stk.back().fir,i)==i)break; rm.push_back(stk.back().fir); stk.pop_back(); } if(!stk.empty()){ int p=stk.back().fir; stk.pop_back(); while(!stk.empty()&&stk.back().sec&&ask(stk.back().fir,i)!=stk.back().fir) stk.pop_back(); stk.emplace_back(p,0); } reverse(allc(rm)); for(auto p:rm)stk.emplace_back(p,1); stk.emplace_back(i,0); rs[i]=stk; } cout<<'!'<<endl; cin>>m; while(m--){ int l,r;cin>>l>>r; stk=rs[r]; int p=0,q=0; while(!stk.empty()&&stk.back().fir>=l){ auto [x,tp]=stk.back();stk.pop_back(); if(tp)q=x;else q=p,p=x; } cout<<q<<'\n'; } ```