题解:P8530 [Ynoi2003] 博丽灵梦
更好的阅读体验
卡了 117 发卡过的,必须纪念一下。
我们先来研发一个数据结构,需要支持在一个
保证任意时刻所有未被删除的点横坐标互不相同,纵坐标互不相同。
这就是二维分块干的事情。
为了解决这个问题,我们考虑将这个
不难发现大块共有
对于修改,假设插入点
对于删除,同样找到要删除的点所属的块,然后减去删除的点的点权即可,显然也可以做到
对于查询,我们稍微差分一下,变成询问一个左下角矩形内部的点权之和。
容易发现,一个左下角矩形应该包含
- 红色的整块(大块):总共
O(\sqrt n) 个。 - 蓝色的整块(中块):总共
O(n^{1/4} \cdot n^{1/4}) = O(\sqrt n) 个。 - 黄色的整块(中块):同上,总共
O(\sqrt n) 个。 - 绿色的整块(小块):总共
O(n^{1/4} \cdot n^{1/4}) = O(\sqrt n) 个。 - 灰色的散块。
对于前四个部分,可以直接枚举这些块并求和。然而对于散块,我们只能枚举散块内部的单点。
但是注意到由于所有点的
这样,查询就做到了
接下来看这个题:矩形带权数颜色。
我们考虑一维的数颜色怎么做。我们选取每个颜色第一次出现的位置为代表元进行统计。具体地,我们对每个位置
那么对于二维的情形,我们对
我们且称
现在问题就是如何支持加点,删点,动态维护
我们考虑对纵轴维护一个双向链表,也就是我们多维护一个
每一次莫队的删除或撤销都对应着
所以我们对于所有
那么这道题就做完了,复杂度
代码删除了快速读入的部分。
#include<bits/stdc++.h>
// #pragma GCC target("avx")
#define endl '\n'
#define N 100006
#define M 1000006
#define cl(t) memset((t),0,sizeof(t))
using namespace std;
struct IO {} io;
using u32=unsigned;
int n,q,tp,B,bel[N],p[N],a[N],nxt[N],pre[N],tmp[N],buc[N];
u32 b[N],ans[M];
struct Ask {
int l,r,L,R,id;
} ask[M];
struct Stack_Node {
int x,pre,nxt,col;
} stk[M];
namespace ds1 {
constexpr int all=100489,B=317;
u32 s1[all+10],s2[B+10];
void clear() {cl(s1),cl(s2);}
void del(int k) {s2[(k-1)/B+1]-=s1[k],s1[k]=0;}
void add(int k,u32 val) {s1[k]+=val,s2[(k-1)/B+1]+=val;}
u32 query(int k)
{
u32 ret=0; int bel=(k-1)/B+1;
for(int i=1;i<bel;i++)ret+=s2[i];
for(int i=(bel-1)*B+1;i<=k;i++)ret+=s1[i];
return ret;
}
}
namespace ds2 {
constexpr int all=1e5,Big=7000,Small=350,Div=20;
u32 s1[all/Big+5][all/Big+5]; //xbig * ybig
u32 s2[all/Big+5][all/Small+5]; //xbig * ysmall
u32 s3[all/Small+5][all/Big+5]; //xsmall * ybig
u32 s4[all/Small+5][all/Small+5]; //xsmall * ysmall
u32 sx[N],sy[N];
int ix[N],iy[N];
inline void clear()
{
for(int i=0;i<all/Big+5;i++)
for(int j=0;j<all/Big+5;j++)s1[i][j]=0;
for(int i=0;i<all/Big+5;i++)
for(int j=0;j<all/Small+5;j++)s2[i][j]=0;
for(int i=0;i<all/Small+5;i++)
for(int j=0;j<all/Big+5;j++)s3[i][j]=0;
for(int i=0;i<all/Small+5;i++)
for(int j=0;j<all/Small+5;j++)s4[i][j]=0;
for(int i=0;i<all+10;i++)
sx[i]=sy[i]=ix[i]=iy[i]=0;
}
inline void Del(int x,int y)
{
if(!ix[x])return;
u32 val=sx[x];
int x_b=(x-1)/Big+1,y_b=(y-1)/Big+1;
int x_s=(x-1)/Small+1,y_s=(y-1)/Small+1;
s1[x_b][y_b]-=val;
s2[x_b][y_s]-=val;
s3[x_s][y_b]-=val;
s4[x_s][y_s]-=val;
sx[x]=sy[y]=ix[x]=iy[y]=0;
}
inline void add(int x,int y,u32 val)
{
sx[x]=val,sy[y]=val,ix[x]=y,iy[y]=x;
int x_b=(x-1)/Big+1,y_b=(y-1)/Big+1;
int x_s=(x-1)/Small+1,y_s=(y-1)/Small+1;
s1[x_b][y_b]+=val;
s2[x_b][y_s]+=val;
s3[x_s][y_b]+=val;
s4[x_s][y_s]+=val;
}
inline u32 query(int x,int y)
{
u32 ret=0;
int x_b=(x-1)/Big+1,y_b=(y-1)/Big+1;
int x_s=(x-1)/Small+1,y_s=(y-1)/Small+1;
int x_lb=(x_b-1)*Div+1,y_lb=(y_b-1)*Div+1;
int x_ls=(x_s-1)*Small+1,y_ls=(y_s-1)*Small+1;
for(int i=1;i<x_b;i++)
for(int j=1;j<y_b;j++)ret+=s1[i][j];
for(int i=1;i<x_b;i++)
for(int j=y_lb;j<y_s;j++)ret+=s2[i][j];
for(int i=x_lb;i<x_s;i++)
for(int j=1;j<y_b;j++)ret+=s3[i][j];
for(int i=x_lb;i<x_s;i++)
for(int j=y_lb;j<y_s;j++)ret+=s4[i][j];
for(int i=x;i>=x_ls;i--)if(ix[i]<=y)ret+=sx[i];
for(int i=y;i>=y_ls;i--)if(iy[i]<x_ls)ret+=sy[i];
return ret;
}
}
namespace ds {
inline void clear() {ds1::clear(),ds2::clear();}
inline void del(int x,int y) {if(!y)ds1::del(x); else ds2::Del(x,y);}
inline void add(int x,int y,u32 val) {if(!y)ds1::add(x,val); else ds2::add(x,y,val);}
inline u32 query(int x,int y) {return ds1::query(x)+ds2::query(x,y);}
}
inline void del(int k)
{
int x=p[k],col=a[k];
ds::del(x,pre[x]),stk[++tp]={x,pre[x],nxt[x],col};
if(nxt[x])ds::del(nxt[x],pre[nxt[x]]),pre[nxt[x]]=pre[x],ds::add(nxt[x],pre[nxt[x]],b[col]);
if(pre[x])nxt[pre[x]]=nxt[x];
pre[x]=nxt[x]=0;
}
inline void undo()
{
int x=stk[tp].x;
int pr=stk[tp].pre,nx=stk[tp].nxt,col=stk[tp].col; tp--;
if(nx)ds::del(nx,pre[nx]),pre[nx]=x,ds::add(nx,pre[nx],b[col]);
if(pr)nxt[pr]=x;
pre[x]=pr,ds::add(x,pre[x],b[col]),nxt[x]=nx;
}
main()
{
n=io.read();
for(int i=1;i<=n;i++)p[i]=io.read();
for(int i=1;i<=n;i++)a[i]=io.read();
for(int i=1;i<=n;i++)b[i]=io.read<u32>();
q=io.read(),B=n/pow(q,0.5);
for(int i=1,l,r,x,y;i<=q;i++)
l=io.read(),r=io.read(),x=io.read(),y=io.read(),ask[i]={l,r,x,y,i};
for(int i=1;i<=n;i++)bel[i]=(i-1)/B+1;
sort(ask+1,ask+1+q,[](Ask x,Ask y) {
if(bel[x.l]!=bel[y.l])return bel[x.l]<bel[y.l];
return x.r>y.r;
});
int l,r,now_l;
for(int i=1;i<=q;i++)
{
if(bel[ask[i].l]!=bel[ask[i-1].l])
{
now_l=l=(bel[ask[i].l]-1)*B+1,r=n,tp=0;
ds::clear(),cl(tmp),cl(pre),cl(nxt),cl(buc);
for(int i=l;i<=r;i++)tmp[p[i]]=a[i];
for(int i=1;i<=n;i++)
if(tmp[i])pre[i]=buc[tmp[i]],buc[tmp[i]]=i,ds::add(i,pre[i],b[tmp[i]]);
for(int i=1;i<=n;i++)if(pre[i])nxt[pre[i]]=i;
}
for(;r>ask[i].r;del(r--));
for(;l<ask[i].l;del(l++));
ans[ask[i].id]=ds::query(ask[i].R,ask[i].L-1)-
ds::query(ask[i].L-1,ask[i].L-1);
for(;l>now_l;undo(),l--);
}
for(int i=1;i<=q;i++)io.writeln<u32>(ans[i]);
return 0;
}