传送门
题解:
考虑保留 [ l , r ] [l,r] [l,r]的点的时候 x x x所在的联通块怎么表示。
考虑点分治的时候第一次把分治中心放到这个联通块里面的那次分治。
取出这个分治中心,则统计颜色就变成了在它子树内部,只通过编号在 [ l , r ] [l,r] [l,r]内的点能够到达多少种不同颜色。
离线,二维数点,树状数组维护一下就没了。
代码:
#include<bits/stdc++.h>
#define ll long long
#define re register
#define cs const
namespace IO{
inline char gc(){
static cs int Rlen=1<<22|1;
static char buf[Rlen],*p1,*p2;
return (p1==p2)&&(p2=(p1=buf)+fread(buf,1,Rlen,stdin),p1==p2)?EOF:*p1++;
}
template<typename T>
inline T get(){
char c;T num;
while(!isdigit(c=gc()));num=c^48;
while(isdigit(c=gc()))num=(num+(num<<2)<<1)+(c^48);
return num;
}
inline int gi(){return get<int>();}
}
using namespace IO;
using std::cerr;
using std::cout;
cs int N=1e5+7;
int n,m;
std::vector<int> G[N];
struct fa_node{int mn,mx,f;};
std::vector<fa_node> fa[N];
struct atom{int mn,mx,id,typ;};
std::vector<atom> q[N];
int siz[N],col[N],ban[N];
int total,maxn,rt;
void get_siz(int u,int p){
siz[u]=1;for(int re v:G[u])
if(v!=p&&!ban[v])get_siz(v,u),siz[u]+=siz[v];
}
void find_rt(int u,int p){
int mx=total-siz[u];for(int re v:G[u])
if(v!=p&&!ban[v])find_rt(v,u),mx=std::max(siz[v],mx);
if(mx<maxn)maxn=mx,rt=u;
}
inline void get_rt(int u){
get_siz(u,-1);
total=siz[u],maxn=1e9;
find_rt(u,-1);
}
void dfs(int u,int p,int mn,int mx){
mn=std::min(mn,u),mx=std::max(mx,u);
fa[u].push_back({mn,mx,rt});
q[rt].push_back({mn,mx,col[u],0});
for(int re v:G[u])if(v!=p&&!ban[v])dfs(v,u,mn,mx);
}
void DFS(int u){
ban[u]=true;dfs(u,-1,u,u);
for(int re v:G[u])if(!ban[v])
get_rt(v),DFS(rt);
}
int las[N],vis[N],tr[N],ans[N];
inline void add(int p,int v){for(;p<N;p+=p&-p)tr[p]+=v;}
inline int query(int p){int res=0;for(;p;p^=p&-p)res+=tr[p];return res;}
signed main(){
#ifdef zxyoi
freopen("ayana.in","r",stdin);
#endif
n=gi(),m=gi();
for(int re i=1;i<=n;++i)col[i]=gi();
for(int re i=1;i<n;++i){
int u=gi(),v=gi();
G[u].push_back(v);
G[v].push_back(u);
}
get_rt(1),DFS(rt);
for(int re i=1;i<=n;++i)assert(ban[i]);
for(int re i=1;i<=m;++i){
int l=gi(),r=gi(),u=gi();
for(auto t:fa[u])if(l<=t.mn&&t.mx<=r)
{q[t.f].push_back({l,r,i,1});break;}
}
for(int re i=1;i<=n;++i){
std::sort(q[i].begin(),q[i].end(),[](cs atom &a,cs atom &b){
return a.mn>b.mn||(a.mn==b.mn&&a.typ<b.typ);
});
for(auto t:q[i])if(t.typ)ans[t.id]=query(t.mx);
else if(vis[t.id]!=i||las[t.id]>t.mx){
if(vis[t.id]==i)add(las[t.id],-1);
add(las[t.id]=t.mx,1);vis[t.id]=i;
}
for(auto t:q[i])if(!t.typ)
for(int re p=t.mx;p<N;p+=p&-p)tr[p]=0;
}
for(int re i=1;i<=m;++i)printf("%d\n",ans[i]);
return 0;
}