莫队
普通莫队
块大小取为\(\sqrt n\)
询问排序时可选择按奇偶性排序
\(code:\)
bool cmp(query a,query b)
{
return (a.r/block)==(b.r/block)?a.l<b.l:a.r<b.r;
}
bool cmp(query a,query b)
{
return a.pos==b.pos?(a.pos&1?a.r<b.r:a.r>b.r):a.pos<b.pos;
}
while(l<ql) del(l++);
while(r>qr) del(r--);
while(l>ql) add(--l);
while(r<qr) add(++r);
带修莫队
将莫队再加上一维,加上时间轴,若当前查询与时间不匹配,则进行时光穿越或时光倒流
块大小取为\(n^\frac{2}{3}\)时最优
\(code:\)
while(l<ql) del(l++);
while(r>qr) del(r--);
while(l>ql) add(--l);
while(r<qr) add(++r);
while(ti<qt)
{
ti++;
int pos=c[ti].pos;
if(l<=pos&&pos<=r)
{
cnt[a[pos]]--;
if(!cnt[a[pos]]) tot--;
}
swap(a[pos],c[ti].col);
if(l<=pos&&pos<=r)
{
cnt[a[pos]]++;
if(cnt[a[pos]]==1) tot++;
}
}
while(ti>qt)
{
int pos=c[ti].pos;
if(l<=pos&&pos<=r)
{
cnt[a[pos]]--;
if(!cnt[a[pos]]) tot--;
}
swap(a[pos],c[ti].col);
if(l<=pos&&pos<=r)
{
cnt[a[pos]]++;
if(cnt[a[pos]]==1) tot++;
}
ti--;
}
树上莫队
先预处理出欧拉序,就是原\(dfs\)序在回溯时又加入序列,每个编号在序列中出现两次
树的欧拉序上两个相同编号之间的所有编号都出现两次,且都位于其子树上
设欧拉序中一个节点\(x\)第一次出现的位置为\(st\),第二次出现的位置为\(ed\)
询问\(x\)和\(y\),设\(st[x] \leqslant st[y]\)
若\(lca(x,y)=x\),则使用区间\([\ st[x],st[y]\ ]\)
反之,使用区间\([\ ed[x],st[y]\ ]\),还需再加上\(lca(x,y)\)
\(code:\)
void dfs_son(int x,int fath)
{
st[x]=++num;
rev[num]=x;
fa[x]=fath;
siz[x]=1;
de[x]=de[fath]+1;
for(int i=head[x];i;i=e[i].nxt)
{
int y=e[i].to;
if(y==fath) continue;
dfs_son(y,x);
siz[x]+=siz[y];
if(siz[y]>siz[son[x]]) son[x]=y;
}
ed[x]=++num;
rev[num]=x;
}
void dfs_chain(int x,int tp)
{
top[x]=tp;
if(son[x]) dfs_chain(son[x],tp);
for(int i=head[x];i;i=e[i].nxt)
{
int y=e[i].to;
if(top[y]) continue;
dfs_chain(y,y);
}
}
int lca(int x,int y)
{
while(top[x]!=top[y])
{
if(de[top[x]]<de[top[y]]) swap(x,y);
x=fa[top[x]];
}
if(de[x]>de[y]) swap(x,y);
return x;
}
struct query
{
int l,r,id,pos,lca;
}q[maxn];
bool cmp(query a,query b)
{
return a.pos==b.pos?(a.pos&1?a.r<b.r:a.r>b.r):a.pos<b.pos;
}
void add(int x)
{
tot+=(++cnt[a[x]]==1);
}
void del(int x)
{
tot-=(--cnt[a[x]]==0);
}
void update(int x)
{
if(!vis[x]) add(x);
else del(x);
vis[x]^=1;
}
......
dfs_son(1,0);
dfs_chain(1,1);
for(int i=1;i<=m;++i)
{
int x,y,anc;
read(x),read(y);
if(st[x]>st[y]) swap(x,y);
anc=lca(x,y);
if(anc==x) q[i]=(query){st[x],st[y],i,st[x]/block,0};
else q[i]=(query){ed[x],st[y],i,ed[x]/block,anc};
}
sort(q+1,q+m+1,cmp);
for(int i=1;i<=m;++i)
{
int ql=q[i].l,qr=q[i].r,id=q[i].id,anc=q[i].lca;
while(l<ql) update(rev[l++]);
while(r>qr) update(rev[r--]);
while(l>ql) update(rev[--l]);
while(r<qr) update(rev[++r]);
if(anc) update(anc);
ans[id]=tot;
if(anc) update(anc);
}