莫队

普通莫队

块大小取为(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);
}
原文地址:https://www.cnblogs.com/lhm-/p/12229611.html