UVA12424 Answering Queries on a Tree

\(\texttt{Description}\)

UVA 题目链接

洛谷题目链接

PDF 题面

  • \(n\) 个节点的树。第 \(i\) 个节点颜色为 \(C_i\)。有 \(m\) 次操作:

    • \(\texttt{0 }u\texttt{ }c\):把 \(C_u\) 改为 \(c\)

    • \(\texttt{1 }u\texttt{ }v\):询问 \(u,v\) 两点路径之间出现最多的颜色次数。

  • \(T\) 组数据,\(1\le T,C_i,c\le 10\)\(1\le n,m\le 10^5\)\(1\le u,v\le n\)

\(\texttt{Solution}\)

有一句话我已经说烂了:

洛谷 P3313 一样,对于这类维护颜色的问题,可以考虑使用动态开点线段树来解决。

于是我也想用类似的套路过这题。但是颜色只有 \(10\) 种,所以根本不用动态开点线段树,搞 \(10\) 棵树状数组就行了。

具体做法是,先树链剖分转化成序列问题,再用树状数组维护每种颜色的前缀个数。修改时,先将原颜色中该位置上 \(-1\),再在新颜色中该位置上 \(+1\)。然后把颜色(\(C\) 数组)改为新颜色,因为下一次修改是针对这个新颜色的。

查询的时候每一条重链上,每种颜色用树状数组前缀个数相减得到个数,再加到总个数上。最后输出最大值即可。

时间复杂度为 \(\mathcal{O}(m\log^2n)\),空间复杂度为 \(\mathcal{O}(n)\),可以接受。

\(\texttt{Code}\)

关于代码:

  • 多测清空。

  • 题解代码的数组和原题定义略有不同。

  • 可以使用指令集卡常。

$\texttt{Click for Code}$
#pragma GCC optimize("Ofast")
#include<bits/stdc++.h>
#define N 100005
using namespace std;
int T,n,m,a[N],dfn[N],f[N],t[N],h[N],sz[N],d[N],ans[15];
vector<int>g[N];
struct tree{
    int sum[N];
    void modify(int x,int k){
        for(int i=x;i<=n;i+=i&-i){
            sum[i]+=k;
        }
    }
    int query(int x){
        int ret=0;
        for(int i=x;i;i-=i&-i){
            ret+=sum[i];
        }
        return ret;
    }
}bit[15];
void dfs1(int u,int fa){
    sz[u]=1;
    for(int v:g[u]){
        if(v^fa){
            d[v]=d[u]+1;
            dfs1(v,f[v]=u);
            sz[u]+=sz[v];
        }
    }
}
void dfs2(int u,int fa){
    for(int v:g[u]){
        if(v^fa){
            if((sz[v]<<1)>sz[u]){
                t[h[u]=v]=t[u];
            }else{
                t[v]=v;
            }
            dfs2(v,u);
        }
    }
}
void dfs3(int u,int fa){
    bit[a[u]].modify(dfn[u]=++dfn[0],1);
    if(h[u]){
        dfs3(h[u],u);
    }
    for(int v:g[u]){
        if((v^fa)&&(v^h[u])){
            dfs3(v,u);
        }
    }
}
void pathquery(int u,int v){
    memset(ans,0,sizeof ans);
    while(t[u]^t[v]){
        if(d[t[u]]<d[t[v]]){
            swap(u,v);
        }
        for(int i=1;i<=10;++i){
            ans[i]+=bit[i].query(dfn[u])-bit[i].query(dfn[t[u]]-1);
        }
        u=f[t[u]];
    }
    if(d[u]>d[v]){
        swap(u,v);
    }
    for(int i=1;i<=10;++i){
        ans[i]+=bit[i].query(dfn[v])-bit[i].query(dfn[u]-1);
    }
    printf("%d\n",*max_element(ans+1,ans+11));
}
int main(){
    scanf("%d",&T);
    while(T--){
        memset(g,0,sizeof g);
        memset(dfn,0,sizeof dfn);
        memset(a,0,sizeof a);
        memset(f,0,sizeof f);
        memset(h,0,sizeof h);
        memset(t,0,sizeof t);
        memset(d,0,sizeof d);
        memset(sz,0,sizeof sz);
        for(int i=1;i<=10;++i){
            memset(bit[i].sum,0,sizeof bit[i].sum);
        }
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;++i){
            scanf("%d",a+i);
        }
        for(int i=1,u,v;i^n;++i){
            scanf("%d%d",&u,&v);
            g[u].push_back(v);
            g[v].push_back(u);
        }
        dfs1(1,0);
        dfs2(t[1]=1,0);
        dfs3(1,0);
        for(int i=1,op,x,y;i<=m;++i){
            scanf("%d%d%d",&op,&x,&y);
            if(op){
                pathquery(x,y);
            }else{
                bit[a[x]].modify(dfn[x],-1);
                bit[a[x]=y].modify(dfn[x],1);
            }
        }
    }
}
posted @ 2023-02-25 20:08  lzyqwq  阅读(21)  评论(0)    收藏  举报