[Ynoi2001] 冷たい部屋、一人
题目描述
给定 \(n,m\),以及序列 \(a_1,a_2,\dots,a_n\) 和 \(1,2,\dots,n\) 的排列 \(y_1,y_2,\dots,y_n\),你需要回答 \(m\) 个询问。
对每个询问,给定 \(l,r\),查询:\(\displaystyle\sum\limits_{i=1}^n\sum\limits_{j=i+1}^n [a_i=a_j]\cdot\prod_{k=i}^j [l\le y_k\le r]\)。
其中 \([\mathrm{cond}]\) 在条件 \(\mathrm{cond}\) 为真时值为 \(1\),否则值为 \(0\)。
对于 \(100\%\) 的数据,满足 \(1\le n,m\le 5\times 10^5\);\(1\le a_i\le n\);\(1\le y_i\le n\),\(y_i\) 互不相同;对每个询问,\(1\le l\le r\le n\)。
对于 \(20\%\) 的数据,满足 \(n,m\le 100\)。
对于 \(40\%\) 的数据,\(n,m\le 5000\)
对于 \(60\%\) 的数据,\(n,m\le 2\times 10^5\)
\(\rm 9s.\)
题解
考虑阈值分治。
对于出现次数小于 \(\sqrt n\) 的颜色,直接枚举相同颜色的点对数,利用 \(O(1)-O(\sqrt n)\) 的分块二维数点解决。需要注意的是,直接做的空间复杂度是 \(O(n\sqrt n)\) 的。令 \([i,j]\) 为相邻的两个相同颜色的点,则应该储存形如 \(\{[l,i],[j,r]\}\) 的四元组,其中 \(l\) 表示最小的满足 $ a_l\gt\min{[i,j]}$ 的 \(l\),\(r\) 同理。换而言之,\(u\in[l,i],v\in[j,r]\Leftrightarrow\min\{[u,v]\}=\min\{[i,j]\}\)。这步可以用单调栈实现,时间复杂度不变,空间复杂度变为 \(O(n)\)。
对于出现次数大于 \(\sqrt n\) 的颜色,每种颜色分开进行处理。使用回滚莫队+链表单次可以做到 \(O(n\sqrt m)\)。离散化之后总时间复杂度为 \(O(n\sqrt m)\)。
实现难度巨大。
代码
#include<bits/stdc++.h>
using namespace std;
#define ssiz(x) (signed)x.size()
const int N=5e5+9;
const int Sqr=7.1e2+9;
const int lgN=2e1;
int a[N],p[N],ql[N],qr[N],n,m,B;
vector<int> pos[N];
long long ans[N];
int maxx[N][lgN],minn[N][lgN],lg[N];
void Init(){
for(int i=2;i<=n;i++) lg[i]=lg[i>>1]+1;
for(int i=1;i<=n;i++) maxx[i][0]=minn[i][0]=p[i];
for(int k=1;k<=lg[n];k++){
for(int i=1;i<=n;i++){
maxx[i][k]=max(maxx[i][k-1],maxx[i+(1<<k-1)][k-1]);
minn[i][k]=min(minn[i][k-1],minn[i+(1<<k-1)][k-1]);
}
}
}
int Max(int l,int r){
int k=lg[r-l+1];
return max(maxx[l][k],maxx[r-(1<<k)+1][k]);
}
int Min(int l,int r){
int k=lg[r-l+1];
return min(minn[l][k],minn[r-(1<<k)+1][k]);
}
vector<array<vector<int>::iterator,3>> seg[N];
vector<pair<int,int>> qry[N];
int blk[N],L[N],R[N];
long long s[N],bs[Sqr];
void Modify(int x,int k){bs[blk[x]]+=k,s[x]+=k;}
long long Brute(int l,int r){
if(l==L[blk[l]]&&r==R[blk[r]]) return bs[blk[l]];
long long sum=0;
for(int i=l;i<=r;i++) sum+=s[i];
return sum;
}
long long Query(int l,int r){
if(blk[l]==blk[r]) return Brute(l,r);
long long sum=Brute(l,R[blk[l]])+Brute(L[blk[r]],r);
for(int i=blk[l]+1;i<blk[r];i++) sum+=bs[i];
return sum;
}
vector<pair<int,int>> lnk[N];
int low[N],up[N],st[N],ed[N],lq[N],rq[N],top;
vector<int> val,tmp[N];
pair<int,int> rb[N<<2];
void Link(int x,long long &res){
res+=1ll*(ed[x]-st[x]+1)*(ed[x+1]-st[x+1]+1);
ed[st[x]]=ed[x+1],st[ed[x+1]]=st[x];
}
void RLink(int x,long long &res){
rb[++top]={st[x],ed[x]};
rb[++top]={st[x+1],ed[x+1]};
Link(x,res);
}
void Rollback(){
while(top){
int x=rb[top].first,y=rb[top].second;
st[x]=st[y]=x,ed[x]=ed[y]=y;
top--;
}
}
long long Brute(long long res,int ql,int l,int r){
while(l>ql){
l--;
for(auto p:lnk[l]) if(p.first>=l&&r>=p.first) RLink(p.second,res);
}
Rollback();
return res;
}
void MoAlgo(int len){
int lim=ssiz(val),B=min((int)ceil(lim/sqrt(m)/1.5),lim);
for(int i=0;i<lim;i++) blk[i]=i/B+1;
for(int i=0;i<lim;i++) R[blk[i]]=i;
for(int i=lim-1;~i;i--) L[blk[i]]=i;
for(int i=1;i<=m;i++) lq[i]=low[ql[i]],rq[i]=up[qr[i]]-1;
vector<int> c;
for(int i=1;i<=m;i++) if(lq[i]<=rq[i]) tmp[rq[i]].push_back(i);
for(int i=0;i<lim;i++){
c.insert(c.end(),tmp[i].begin(),tmp[i].end());
tmp[i].clear();
}
for(int x:c) if(lq[x]<=rq[x]) tmp[blk[lq[x]]].push_back(x);
c.clear();
for(int i=1;i<=blk[lim-1];i++){
for(int j=0;j<len;j++) st[j]=ed[j]=j;
long long res=0;int l=R[i]+1,r=R[i];
for(int j:tmp[i]){
if(rq[j]<=R[i]){
ans[j]+=Brute(res,lq[j],rq[j]+1,rq[j]);
continue ;
}
while(r<rq[j]){
r++;
for(auto p:lnk[r]) if(p.first<=r&&l<=p.first) Link(p.second,res);
}
ans[j]+=Brute(res,lq[j],l,r);
}
tmp[i].clear();
}
}
int main(){
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
#define endl '\n'
cin>>n>>m;
for(int i=1;i<=n;i++) cin>>a[i],pos[a[i]].push_back(i);
for(int i=1;i<=n;i++) cin>>p[i];
for(int i=1;i<=m;i++) cin>>ql[i]>>qr[i];
B=sqrt(n),Init();
for(int i=1;i<=n;i++){
if(ssiz(pos[i])<2||ssiz(pos[i])>2*B) continue ;
vector<pair<int,int>> tmp;
for(int j=1;j<ssiz(pos[i]);j++) tmp.push_back({Min(pos[i][j-1],pos[i][j]),j});
vector<int> stk,lp(ssiz(pos[i]),0),rp(ssiz(pos[i]),ssiz(pos[i])-1);
for(int j=0;j<ssiz(tmp);j++){
while(ssiz(stk)&&tmp[stk.back()]>tmp[j]) stk.pop_back();
if(ssiz(stk)) lp[j]=stk.back()+1;
stk.push_back(j);
}
stk.clear();
for(int j=ssiz(tmp)-1;~j;j--){
while(ssiz(stk)&&tmp[stk.back()]>tmp[j]) stk.pop_back();
if(ssiz(stk)) rp[j+1]=stk.back();
stk.push_back(j);
}
auto it=pos[i].begin();
for(int j=0;j<ssiz(tmp);j++) seg[tmp[j].first].push_back({it+lp[j],it+j+1,it+rp[j+1]+1});
}
for(int i=1;i<=m;i++) qry[ql[i]].push_back({i,qr[i]});
for(int i=1;i<=n;i++) blk[i]=(i-1)/B+1;
for(int i=1;i<=n;i++) R[blk[i]]=i;
for(int i=n;i>=1;i--) L[blk[i]]=i;
for(int i=n;i>=1;i--){
for(auto t:seg[i]){
for(auto lt=t[0];lt!=t[1];lt++){
for(auto rt=t[1];rt!=t[2];rt++) Modify(Max(*lt,*rt),1);
}
}
for(auto p:qry[i]) ans[p.first]+=Query(1,p.second);
}
for(int i=1;i<=n;i++){
if(ssiz(pos[i])<=2*B) continue ;
val.clear();
for(int j=0;j<ssiz(pos[i])-1;j++){
val.push_back(Min(pos[i][j],pos[i][j+1]));
val.push_back(Max(pos[i][j],pos[i][j+1]));
}
val.push_back(0),val.push_back(n+1);
sort(val.begin(),val.end());
val.erase(unique(val.begin(),val.end()),val.end());
for(int j=0,it=0,jt=0;j<=n;j++){
while(val[it]<j) it++;low[j]=it;
while(val[jt]<=j) jt++;up[j]=jt;
lnk[j].clear();
lnk[j].reserve(8);
}
for(int j=0;j<ssiz(pos[i])-1;j++){
int mn=Min(pos[i][j],pos[i][j+1]),mx=Max(pos[i][j],pos[i][j+1]);
lnk[low[mn]].push_back({low[mx],j});
lnk[low[mx]].push_back({low[mn],j});
}
MoAlgo(ssiz(pos[i]));
}
for(int i=1;i<=m;i++) cout<<ans[i]<<endl;
return 0;
}

浙公网安备 33010602011771号