题解 P7721【[Ynoi2007] rcn】
题意
给你 $n$ 个点 $(i,p_i)$,其中 $p$ 是一个 $n$ 阶排列。第 $i$ 个点有颜色 $a_i$,每种颜色有一个权值 $b_i$。有 $m$ 次询问,每次询问给出 $l_1,r_1,l_2,r_2$,求出 $\displaystyle\sum_{k=1}^nb_k\left[\sum_{i=l_1}^{r_1}[l_2\le p_i\le r_2][a_i=k]\right]$,即求矩阵颜色权值和。
时间 7.5s,$1\le p_i,a_i\le n\le 10^5,1\le m\le 10^6$.
思路
前置知识:P7448 [Ynoi2007] rdiq(最好会但不一定需要)
虽然不卡常,但是 $10^6$ 的数据范围用意何在? update:lxl:1e6卡四维莫队呗。
我码力好差,写了三天/kel
首先可以想到对 $x$ 轴做莫队,然后是要做在 $y$ 轴上单点修改区间数颜色(这是因为 $y$ 轴不重复)。
记 $rp_{p_i}=i,c_i=a_{p_i}$,以下讨论都是在 $y$ 坐标上的。
这个修改其实是在序列上插入/删除,求区间颜色数,那么用链表(或者其它的数据结构)维护每个颜色,记上一个颜色为 $c_i$ 的点(按 $y$ 坐标排序)的 $y$ 坐标为 $pre_i$,则插入删除是单点修改(加),查询是二维数点。可惜我们插入时要在线查询前驱,这里会带上 $\log$。
把莫队回滚,变成不插入莫队,我们便只需要删除,用链表可以做到。
现在需要支持的是 $O(1)-O(\sqrt n)$ 的单点加矩形求和的数据结构。看着眼熟。事实上,这里单点加的点只有 $(i,pre_i)$,$y$ 坐标几乎是时刻不重复的。为什么是几乎?因为 $pre_i=0$ 的点会有很多。那么我们将这些点取出来,对于点 $(i,j)(j\ne 0)$,$j$ 是不重复的,采用 $\text{rdiq}$ 中的二维分块结构,实时更新每个 $x$ 对应的 $y$(和 $y$ 对应的 $x$),对于点 $(i,j)(j=0)$,我们写一个一维分块维护即可。
时间复杂度是 $O(n\sqrt m+m\sqrt n)$,空间复杂度是 $O(n+m)$。注意莫队块长是 $\dfrac{n}{\sqrt m}$,不要让时间复杂度带上 $O(m\sqrt m)$。
这道题还是有一定启发性的,对于高维的范围查询问题,可以使用莫队解决其中一些维度,数据结构维护其余维度来做到更优秀的复杂度。当这里使用莫队维护一维,数据结构维护三维时,实际上等价于一个带修改的三维问题,因为一维的莫队就是一个扫描线,也可以看出莫队实际上是一个二维的扫描线。——lxl
这题不怎么卡常,只要你复杂度正确,常数不离谱基本上不会被卡。
以下代码仅供参考,请勿抄袭。
细节巨多的代码:
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define ui unsigned
namespace IO{//by cyffff
}
const int N=1e5+10,M=1e6+10,sq1=317,sq2=5706,nq1=N/sq2+10,nq2=N/sq1+10;
int p[N],a[N],b[N],c[N],rp[N],curL,curR;
int blo,bel[N];
int n,m,k;
ui ans[M];
struct query{
int l,r,id;
inline friend bool operator<(const query &a,const query &b){
return bel[a.l]==bel[b.l]?a.r>b.r:bel[a.l]<bel[b.l];
}
}q[M];
struct Matrix{
int l1,r1,l2,r2;
}sav[M];
struct Delete{
int pre,suf,ind;
}tem[N];
int pre[N],suf[N],las[N],fir[N];
struct Two_D_Blocker{
int bel1[N],bel2[N],bl1[N],bl2[N],sz1,sz2;
int P[N],rP[N];
ui s1[nq1][nq1],s2[nq2][nq1],s3[nq1][nq2],s4[nq2][nq2],s5[N],s6[N];
ui a[N],sum[nq2];
inline void init(){
for(int i=1;i<=n;i++)
rp[p[i]]=i;
for(int i=1;i<=n;i++)
bel1[i]=(i-1)/sq1+1,
bel2[i]=(i-1)/sq2+1;
for(int i=n;i>=1;i--)
bl1[bel1[i]]=i,
bl2[bel2[i]]=bel1[i];
}
inline void modify(int x,int y,ui v){
if(y==0){
sum[bel1[x]]+=v,a[x]+=v;
return ;
}
int x1=bel1[x],x2=bel2[x],y1=bel1[y],y2=bel2[y];
s1[x2][y2]+=v;
s2[x1][y2]+=v;
s3[x2][y1]+=v;
s4[x1][y1]+=v;
s5[x]+=v,s6[y]+=v;
P[x]=y,rP[y]=x;
}
inline ui query(int x,int y){
if(!x) return 0;
ui ans=0;
int x1=bel1[x],x2=bel2[x],y1=bel1[y],y2=bel2[y];
int qx=bl1[x1],px=bl2[x2],qy=bl1[y1],py=bl2[y2];
for(int i=1;i<x2;i++)
for(int j=1;j<y2;j++)
ans+=s1[i][j];
for(int i=px;i<x1;i++)
for(int j=1;j<y2;j++)
ans+=s2[i][j];
for(int i=1;i<x2;i++)
for(int j=py;j<y1;j++)
ans+=s3[i][j];
for(int i=px;i<x1;i++)
for(int j=py;j<y1;j++)
ans+=s4[i][j];
for(int i=qx;i<=x;i++)
if(P[i]<=y)
ans+=s5[i];
for(int i=qy;i<=y;i++)
if(rP[i]<qx)
ans+=s6[i];
for(int i=1;i<x1;i++)
ans+=sum[i];
for(int i=qx;i<=x;i++)
ans+=a[i];
return ans;
}
inline void clear(){
memset(s1,0,sizeof(s1));
memset(s2,0,sizeof(s2));
memset(s3,0,sizeof(s3));
memset(s4,0,sizeof(s4));
memset(s5,0,sizeof(s5));
memset(s6,0,sizeof(s6));
memset(a,0,sizeof(a));
memset(sum,0,sizeof(sum));
}
}ds;
inline ui query(int id){
int l1=sav[id].l2,r1=sav[id].r2,r2=sav[id].l2-1;
return ds.query(r1,r2)-ds.query(l1-1,r2);
}
bool vis[N];
inline ui calc(int id){
int l1=sav[id].l1,r1=sav[id].r1,l2=sav[id].l2,r2=sav[id].r2;
ui ans=0;
for(int i=l1;i<=r1;i++)
if(l2<=p[i]&&p[i]<=r2&&!vis[a[i]])
vis[a[i]]=1,ans+=b[a[i]];
for(int i=l1;i<=r1;i++)
vis[a[i]]=0;
return ans;
}
inline void init2(int bL){
memset(las,0,sizeof(las));
memset(pre,0,sizeof(pre));
memset(suf,0,sizeof(suf));
for(int i=1;i<=n;i++)
if(rp[i]>=bL) pre[i]=las[c[i]],las[c[i]]=i;
memset(las,0,sizeof(las));
for(int i=n;i>=1;i--)
if(rp[i]>=bL) suf[i]=las[c[i]],las[c[i]]=i;
}
int main(){
// freopen("make_data.in","r",stdin);
n=read();
for(int i=1;i<=n;i++)
p[i]=read();
for(int i=1;i<=n;i++)
a[i]=read(),c[p[i]]=a[i];
for(int i=1;i<=n;i++)
b[i]=read();
m=read();
for(int i=1;i<=m;i++){
int l1=read(),r1=read(),l2=read(),r2=read();
sav[i]={l1,r1,l2,r2};
q[i]={l1,r1,i};
}
ds.init();
blo=n/sqrt(m);
for(int i=1;i<=n;i++)
bel[i]=(i-1)/blo+1;
sort(q+1,q+m+1);
for(int i=1,j=1,bL=1;i<=bel[n];i++,bL+=blo){
int bR=min(n,bL+blo-1);
if(bel[q[j].l]!=i) continue;
curL=bL-1,curR=n;
init2(bL);
for(int i=bL;i<=n;i++)
ds.modify(p[i],pre[p[i]],b[a[i]]);
for(;bel[q[j].l]==i;j++){
int L=q[j].l,R=q[j].r,top=0;
if(bel[R]==i){
ans[q[j].id]=calc(q[j].id);
continue;
}
curL=bL;
while(curR>R){
int t=p[curR];
if(suf[t])
ds.modify(suf[t],t,-b[c[suf[t]]]),pre[suf[t]]=pre[t];
ds.modify(t,pre[t],-b[c[t]]);
if(pre[t])
suf[pre[t]]=suf[t];
if(suf[t])
ds.modify(suf[t],pre[t],b[c[suf[t]]]);
curR--;
}
while(curL<L){
int t=p[curL];
tem[++top]={pre[t],suf[t],t};
if(suf[t])
ds.modify(suf[t],t,-b[c[suf[t]]]),pre[suf[t]]=pre[t];
ds.modify(t,pre[t],-b[c[t]]);
if(pre[t])
suf[pre[t]]=suf[t];
if(suf[t])
ds.modify(suf[t],pre[t],b[c[suf[t]]]);
curL++;
}
ans[q[j].id]=query(q[j].id);
while(top){
Delete tmp=tem[top--];
if(tmp.suf)
ds.modify(tmp.suf,pre[tmp.suf],-b[c[tmp.suf]]),pre[tmp.suf]=tmp.ind;
ds.modify(tmp.ind,tmp.pre,b[c[tmp.ind]]);
pre[tmp.ind]=tmp.pre,suf[tmp.ind]=tmp.suf;
if(tmp.pre)
suf[tmp.pre]=tmp.ind;
if(tmp.suf)
ds.modify(tmp.suf,pre[tmp.suf],b[c[tmp.suf]]);
}
}
ds.clear();
}
for(int i=1;i<=m;i++)
write(ans[i]),putc('\n');
flush();
}
再见 qwq~

浙公网安备 33010602011771号