树上莫队复习

树上莫队复习

被开业 D 了所以就来写 md

定义

树🌲上的莫队

应用

[SDOI2018]原题识别

  • 给你一棵 \(n\) 个节点的树,每个节点有一个颜色
  • 让你求 \(u\)\(v\) 的路径上不同颜色点的个数

前置知识

欧拉序

  • 入的时候加一次,出的时候加一次
  • 用于把树上问题抓换到序列上

树上莫队

  • 考虑解决一开始的问题
  • \(st_i\) 表示 \(i\) 点入的时间,\(ed_i\) 表示 \(i\) 点出的时间
  • 不妨设 \(st_x<st_y\) (先访问 \(x\) 后访问 \(y\)
  • \({\rm lca}(x,y)=x\) ,那么 \(x,y\) 处于同一条链上
  • 于是我们仅需要统计 \(st_x\sim st_y\) 这一段上出现过一次的点
  • 否则,此时 \(x,y\) 位于不同子树内,我们仅需统计 \(ed_x\sim st_y\) 以及 \(\rm lca\) 即可
  • 因为 \(st_x\sim ed_x\)\(x\) 为根的子树
  • 然后,树上的问题成功被我们转化到序列上
  • 剩下的交给莫队解决

代码

/*************************************************************************
    > File Name: code.cpp
    > Author: Typedef 
    > Mail: 1815979752@qq.com 
    > Created Time: 2021-10-07 08:17:32
    > blog: https://www.cnblogs.com/Illyasviel
************************************************************************/
#include<bits/stdc++.h>
using namespace std;
const int N=4e5+7,RT=1e3+7;
int h[N],e[N<<1],ne[N<<1],idx=0;
int idfn[N<<1],st[N],ed[N],timestamp=0;
int fa[N],dep[N],son[N],top[N],sz[N];
int n,m;
inline void add(int a,int b){
    e[idx]=b,ne[idx]=h[a],h[a]=idx++;
}
void dfs0(int u,int father){
    st[u]=++timestamp;
    idfn[timestamp]=u;
    dep[u]=dep[father]+1;
    son[u]=0,sz[u]=1,fa[u]=father;
    for(int i=h[u];~i;i=ne[i]){
        int v=e[i];
        if(v==father) continue;
        dfs0(v,u);
        sz[u]+=sz[v];
        if(sz[son[u]]<sz[v]) son[u]=v; 
    }
    ed[u]=++timestamp;
    idfn[timestamp]=u;
}
void dfs1(int u){
    if(son[u]){
        top[son[u]]=top[u];
        dfs1(son[u]);
    }
    for(int i=h[u];~i;i=ne[i]){
        int v=e[i];
        if(v==fa[u]||v==son[u]) continue;
        top[v]=v,dfs1(v);
    }
}
int lca(int x,int y){
    while(top[x]!=top[y]){
        if(dep[top[x]]<dep[top[y]])
            x^=y^=x^=y;
        x=fa[top[x]];
    }
    return dep[x]<dep[y]?x:y;
}
int a[N],b[N],cnt[N<<1];
bool vis[N];
int ans[N];
int len=0,res=1;
int l=1,r;
inline int getid(int x){
    return (x-1)/len;
}
inline void add(int x){
    // puts("a");
    if(!cnt[a[x]]) res++;
    cnt[a[x]]++;
}
inline void del(int x){
    // puts("d");
    cnt[a[x]]--;
    if(!cnt[a[x]]) res--;
}
inline void mov(int x){
    if(vis[x]) del(x);
    else add(x);
    vis[x]^=1;
}
struct Query{
    int l,r;
    int anc,id;
    friend bool operator<(const Query &a,const Query &b){
        return getid(a.l)==getid(b.l)?((getid(a.l)&1)?(a.r<b.r):(a.r>b.r)):getid(a.l)<=getid(b.l);
    }
}q[N];
template<class T>void qread(T &x){
    x=0;bool f=0;char c=getchar();
    while(c<'0'||c>'9'){if(c=='-') f=1;c=getchar();}
    while(c>='0'&&c<='9'){x=(x<<3)+(x<<1)+(c^48);c=getchar();}
    if(f) x=-x;
}
template<class T>void print(T x,char c='\n'){
    vector<char> stk;
    if(x<0) putchar('-'),x=-x;
    while(x) stk.push_back(x%10+'0'),x/=10;
    while(!stk.empty()) putchar(stk.back()),stk.pop_back();
    putchar(c);
}
int main(){
    // freopen("in.txt","r",stdin);
    // freopen("out.txt","w",stdout);
    memset(h,-1,sizeof(h));
    qread(n),qread(m);
    len=(int)sqrt(n);
    for(int i=1;i<=n;i++)
        qread(a[i]);
    memcpy(b,a,sizeof(a));
    sort(b+1,b+n+1);
    int tot=unique(b+1,b+n+1)-b-1;
    for(int i=1;i<=n;i++)
        a[i]=lower_bound(b+1,b+tot+1,a[i])-a;
    ans[1]=0,top[1]=1;
    for(int i=1;i<n;i++){
        int x,y;
        qread(x),qread(y);
        add(x,y),add(y,x);
    }
    dfs0(1,0),dfs1(1);
    for(int i=1;i<=m;i++){
        int x,y;
        qread(x),qread(y);
        q[i].anc=lca(x,y);
        q[i].id=i;
        if(st[x]>st[y])
            x^=y^=x^=y;
        q[i].r=st[y];
        if(q[i].anc==x)
            q[i].l=st[x],q[i].anc=0;
        else q[i].l=ed[x];
    }
    sort(q+1,q+m+1);
    for(int i=1;i<=m;i++){
        int ql=q[i].l,qr=q[i].r;
        while(r<qr) mov(idfn[++r]);
        while(r>qr) mov(idfn[r--]);
        while(l<ql) mov(idfn[l++]);
        while(l>ql) mov(idfn[--l]);
        if(q[i].anc) mov(q[i].anc);
        ans[q[i].id]=res;
        if(q[i].anc) mov(q[i].anc);
    }
    for(int i=1;i<=m;i++)
        print(ans[i]-1);
    return 0;
}
/*/
                                                  
                         _________   __  _-----_  
                      __/ ________\_/  \/-------> 
                     / __/        \ (@)_\___      
                    / /    _----- _/  /   \_\_    
                  / /     /          \_      \\   
                 / /     /             \_      \  
                 / /    / _              \        
                / /    / / \___           |       
               / /    / /      \___       /       
               | |   / /           \___  /        
              / /   / /               / /         
              | |  / /               / /          
             / /  / /               / /           
             | | / /               / /            
            /__\/ /               / /             
            |\ _\/__             / /              
           / // /\__\___        / /               
          /_// /    \___\___   / /                
        _/_//  \__      \___\ / /                 
       /  //      \___      \/ /                  
      /  //           \_____/ /                   
     /  //                   /                    
     \_/ \_                 /                     
           \__             /                      
              \___        /                       
                  \_____ /                        
                                                  
*/
posted @ 2021-11-11 14:23  actypedef  阅读(61)  评论(0)    收藏  举报