题解 P7721【[Ynoi2007] rcn】

$\text{Link}$

题意

给你 $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~

posted @ 2022-03-17 13:38  ffffyc  阅读(6)  评论(0)    收藏  举报  来源