Luogu P8543 纯粹的复仇女神
Description
Solution
感觉不算很套路的 DS 题吧,想了 1h 才会。
考虑对每种颜色分开考虑。假设颜色 \(C\) 对应位置 \(\{p_1,p_2,\cdots,p_k\}\),考虑 \(p_k\) 何时会对询问区间 \([ql,qr]\) 产生贡献。令 \(p_i\) 之前 / 之后第一个权值 \(< / \le\) 它的是 \(L_i,R_i\),则 \(ql \in (L_i,p_i],qr \in [p_i,R_i)\) 即 \(p_k=\arg \min_{c_i = k}\{a_i\}\) 的充要条件。
问题转化为:\(n\) 次矩形取 \(\max\),\(q\) 次单点查询。离线下来扫描线,建立一棵线段树并使用 multiset 维护每个点处的标记;碰到上边界时范围插入取 \(\max\) 的标记,碰到下边界时范围删除取 \(\max\) 的标记,查询时答案即链上的每个点处各标记的最大值。时间复杂度 \(O(n \log^2 n+q \log n)\)。
Code
#include <bits/stdc++.h>
#define eb emplace_back
#define fi first
#define se second
#define L (ls[rt])
#define R (rs[rt])
using namespace std;
const int N=2e5+5,M=4e5+5,Q=1e6+5;
namespace IO{
inline char nc(){
static char buf[500001],*p1=buf,*p2=buf;
return p1==p2&&(p2=(p1=buf)+fread(buf,1,500000,stdin),p1==p2)?EOF:*p1++;
}
char out[500001],*pout=out,*eout=out+500000;
template<typename T> inline T read(){
char ch=nc(); T sum=0; bool f=false;
for(;ch<'0'||ch>'9';ch=nc()) if(ch=='-') f=1;
while(ch>='0'&&ch<='9')sum=sum*10+ch-48,ch=nc();
return f ? -sum : sum;
}
}
#define read IO::read<int>
int n,q,m,len,tot,c[N],a[N],stk[N],res[Q]; vector<pair<int,int> >qry[N];
int b[N],frt[N],nxt[N],ls[M],rs[M]; vector<int> vec[N]; priority_queue<int> A[M],B[M];
struct Operation{int l,r,val;};vector<Operation> ins[N],ers[N];
void Contribute(){
stk[len=0]=0;
for (int i=2;i<=m;i++){
while (len&&a[stk[len]]>=a[b[i]]) len--;
frt[i]=stk[len],stk[++len]=b[i];
}
stk[len=0]=n+1;
for (int i=m-1;i;i--){
while (len&&a[stk[len]]>a[b[i]]) len--;
nxt[i]=stk[len],stk[++len]=b[i];
}
for (int i=2;i<m;i++){
int l=frt[i]+1,r=nxt[i]-1,p=b[i];
ins[l].eb(Operation{p,r,a[p]});
ers[p].eb(Operation{p,r,a[p]});
}
}
int build_tree(int l,int r){
int rt=(++tot);
if (l^r){
int mid=(l+r)>>1;
ls[rt]=build_tree(l,mid);
rs[rt]=build_tree(mid+1,r);
}
return rt;
}
void upd(int nl,int nr,int l,int r,int rt,int k,int op){
if (nl<=l&&r<=nr){
if (op) A[rt].push(k);
else B[rt].push(k);
return;
}
int mid=(l+r)>>1;
if (nl<=mid) upd(nl,nr,l,mid,L,k,op);
if (nr>mid) upd(nl,nr,mid+1,r,R,k,op);
}
void query(int nl,int l,int r,int rt,int &res){
if (!A[rt].empty()&&A[rt].top()>res){
while (!A[rt].empty()&&!B[rt].empty()&&A[rt].top()==B[rt].top()) A[rt].pop(),B[rt].pop();
if (!A[rt].empty()) res=max(res,A[rt].top());
}
if (l==r) return;
int mid=(l+r)>>1;
if (nl<=mid) query(nl,l,mid,L,res);
else query(nl,mid+1,r,R,res);
}
int main(){
n=read(),q=read();
for (int i=1;i<=n;i++) c[i]=read(),vec[c[i]].eb(i);
for (int i=1;i<=n;i++) a[i]=read();
for (int i=1;i<=n;i++)if(!vec[i].empty()){
b[m=1]=0;
for (int x:vec[i]) b[++m]=x;
b[++m]=n+1,Contribute();
}
build_tree(1,n);
for (int i=1,l;i<=q;i++) l=read(),qry[l].eb(make_pair(read(),i));
for (int l=1;l<=n;l++){
for (auto t:ins[l]) upd(t.l,t.r,1,n,1,t.val,1);
for (auto t:qry[l]) query(t.fi,1,n,1,res[t.se]);
for (auto t:ers[l]) upd(t.l,t.r,1,n,1,t.val,0);
}
for (int i=1;i<=q;i++) printf("%d\n",res[i]);
return 0;
}

浙公网安备 33010602011771号