题目链接:https://www.luogu.com.cn/problem/P6177
n个点的一棵树m次询问树上颜色。
强制在线
1≤n≤4×105,1≤m≤105,0≤vali<231
把所有深度为√n并且下面至少有√n的深度的点标记,这样保证关键点数量不超过√n。
然后每个点到他周围关键点的距离也不会超过 √n 。
这样可以处理出关键点两两之间的颜色bitset,然后每次路径找两个最近的关键点爆做就好了。
时间复杂度O((m+n)(√n+nω))
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<bitset>
#include<cmath>
using namespace std;
const int N=41000,T=300,M=(4e4)/T+10;
struct node{
int to,next;
}a[N<<1];
int n,m,tot,cnt,sum,fa[N],v[N],top[N],ls[N],d[N],dep[N],w[N],b[N],mark[N],dfn[N],ed[N],g[M][M];
bitset<N> f[M][M],bt;
void addl(int x,int y){
a[++tot].to=y;
a[tot].next=ls[x];
ls[x]=tot;return;
}
void dfs(int x){
for(int i=ls[x];i;i=a[i].next){
int y=a[i].to;
if(y==fa[x])continue;
dep[y]=dep[x]+1;
fa[y]=x;dfs(y);
d[x]=max(d[x],d[y]+1);
}
if(dep[x]%T==0&&d[x]>=T)
mark[x]=++cnt;
return;
}
void dFs(int x){
if(mark[x])top[x]=x;dfn[x]=++cnt;
for(int i=ls[x];i;i=a[i].next){
int y=a[i].to;
if(y==fa[x])continue;
top[y]=top[x];dFs(y);
}
ed[x]=cnt;
return;
}
void calc(int x,int p,int fa){
if(!v[w[x]])bt[w[x]]=1,sum++;v[w[x]]++;
if(mark[x])f[p][mark[x]]=bt,g[p][mark[x]]=sum;
for(int i=ls[x];i;i=a[i].next){
int y=a[i].to;
if(y==fa)continue;
calc(y,p,x);
}
v[w[x]]--;if(!v[w[x]])bt[w[x]]=0,sum--;
return;
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
scanf("%d",&w[i]),b[i]=w[i];
sort(b+1,b+1+n);
int L=unique(b+1,b+1+n)-b-1;
for(int i=1;i<=n;i++)
w[i]=lower_bound(b+1,b+1+L,w[i])-b;
for(int i=1;i<n;i++){
int x,y;
scanf("%d%d",&x,&y);
addl(x,y);addl(y,x);
}
dfs(1);cnt=0;dFs(1);
for(int i=1;i<=n;i++)
if(mark[i])calc(i,mark[i],i);
int last=0;
while(m--){
int x,y;
scanf("%d%d",&x,&y);
x^=last;
if(top[x]==top[y]){
int xx=x,yy=y,ans=0;
while(x!=y){
if(dep[x]<dep[y])swap(x,y);
if(!v[w[x]])ans++,v[w[x]]=1;
x=fa[x];
}
if(!v[w[x]])ans++,v[w[x]]=1;
printf("%d\n",ans);last=ans;
x=xx;y=yy;
while(x!=y){
if(dep[x]<dep[y])swap(x,y);
v[w[x]]=0;x=fa[x];
}
v[w[x]]=0;
}
else{
if(dfn[x]>=dfn[y]&&dfn[x]<=ed[y])swap(x,y);
if(dfn[y]>=dfn[x]&&dfn[y]<=ed[x]){
int z=top[y];
while(top[fa[z]]!=top[x])
z=top[fa[z]];
bt=f[mark[z]][mark[top[y]]];
int ans=g[mark[z]][mark[top[y]]];
while(y!=top[y]){
if(!bt[w[y]])ans++,bt[w[y]]=1;
y=fa[y];
}
while(z!=x){
if(!bt[w[z]])ans++,bt[w[z]]=1;
z=fa[z];
}
if(!bt[w[z]])ans++,bt[w[z]]=1;
printf("%d\n",ans);last=ans;
}
else{
bt=f[mark[top[x]]][mark[top[y]]];
int ans=g[mark[top[x]]][mark[top[y]]];
while(x!=top[x]){
if(!bt[w[x]])ans++,bt[w[x]]=1;
x=fa[x];
}
while(y!=top[y]){
if(!bt[w[y]])ans++,bt[w[y]]=1;
y=fa[y];
}
printf("%d\n",ans);last=ans;
}
}
}
return 0;
}
__EOF__
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 张高兴的大模型开发实战:(一)使用 Selenium 进行网页爬虫
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构