UVA12424 Answering Queries on a Tree
\(\texttt{Description}\)
有 \(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);
}
}
}
}

浙公网安备 33010602011771号