树上莫队(随意看看)

莫队的简单介绍

今天我们简单的来看一下长在树上的莫队
要说莫队是一个很暴力,很高效的算法
考场上的暴力乱搞佳品
网上有国际友人的blog,不过需要一点英语知识(或者是google翻译)

最简单的不修改线性莫队

莫队重点就在于分块(这可是精髓)
一般的,我们就分成sqrt(n)

struct node{
    int x,y,block;
};
node Q[N];
int n;

int cmp(const node &a,const node &b)
{
    if (a.block!=b.block) return a.blockelse return a.y//右端点
}

void init()
{
    scanf("%d",&n);
    int unit=sqrt(n);
    for (int i=1;i<=n;i++)
        scanf("%d%d",&Q[i].x,&Q[i].y),
        Q[i].block=(Q[i].x-1)/unit+1;    //分块 
    sort(Q+1,Q+1+n,cmp);
}

我们看到这里block的计算比较玄妙(记住就好,记住就好,记住就好)
如果分块处理的不好,莫队算法的时间复杂度退化的很厉害(很容易就T掉了)

在处理询问的时候,我们设置两个指针
顺序处理询问,每次暴力维护答案
就以一道题为例:计算区间不同颜色数

int cnt[N];
void doit()
{
    int L=1,R=0,num=0;
    for (int i=1;i<=n;i++)
    {
        while (Rif (cnt[C[R]]==1) num++;
        }
        while (R>Q[i].y)
        {
            cnt[C[R]]--;
            if (cnt[C[R]]==0) num--;
            R--;
        }
        while (L--;
            if (cnt[C[L]]==0) num--;
            L++;
        }
        while (L>Q[i].x)
        {
            L--;
            cnt[C[L]]++;
            if (cnt[C[l]]==1) num++;
        }
        ans[Q[i].id]=num;
    }
}

带修改的线性莫队

实际上思路和朴素的莫队一样
只不过增加了一个修改指针
这里不再冗述,可以去经典例题转一转
(代码挺好理解的)

子树树上莫队

树上莫队是莫队算法的拓展,思想依然差不多

朴素的莫队是在序列上进行的
能把树形结构与序列联系在一起的,最简单的就是dfs序

那么一个子树就对应dfs序上一段,所以我们就可以在dfs序上莫队

路径树上莫队

听说树上莫队只能搞子树询问?
然而外国友人用一个奇技淫巧把ta扩展到了路径询问

对树做一次深搜,第一次进入某节点时,将此节点编号加入序列,从某节点退出时,将此节点编号第二次加入序列
记录一个数在括号序中第一次出现(st)和最后一次出现的位置(ed)

树上莫队(随意看看)_第1张图片

我们假设要询问一条路径a-b,设p=lca(a,b)
不妨设st[a]<=st[b](否则交换一下)

  • 当p=a时,这应该是一个比较简单的情形:a-b是一段父子链
    我们考虑dfs序上[st[a],st[b]]的点,我们可以发现,a-b上的点被算了一遍,其他点都被算了2遍或0遍
    这个时候我们就需要一个玄妙的操作消除影响:
void update(int x,int z)
{
    int co=C[x];
    num-=(bool)cnt[co];    //cnt是color的出现次数 
    cnt[co]-=vis[x]&1;     //vis是结点在序列中出现的次数 
    vis[x]+=z;
    cnt[co]+=vis[x]&1;
    num+=(bool)cnt[co];
}

这是一种比较官方的写法,然而我又YY处理另一种写法(比较好理解)

void update(int x)
{
    int co=C[x],z;
    if (!vis[x]) vis[x]=1,z=1;  
    else vis[x]=0,z=-1;
    if (cnt[co]==0&&z==1) num++;
    cnt[co]+=z;
    if (cnt[co]==0) num--;
}
  • 当p≠a时,我们统计[ed[a],st[b]]的点(从ed[a]开始为保证a不会被排除掉),

但是这回lca并没有统计在内,所以需要另外计算

例题

你可能感兴趣的:(莫队)