GOT - Gao on a tree

这题采用离线处理的方式。

将每个点的点权,以及每次询问的权值分别按从小到大排序。

初始我们有一棵树,每个节点都没有点权。

对于每次询问,将点权小于等于这次询问的权值的点添加上它原本的权值。然后判断一下询问的权值是否等于路径最大值,是则存在,不是则不存在。

这样我们只需要用到单点修改和区间求查询,树剖维护一下即可。

另外注意本题中 \(c\ge 0\),题目可能会询问是否存在点权为 \(0\) 的点,所以不要将节点初始值设为 \(0\)

int n,m,tot,cnt;
int head[maxn],ans[maxn];
int dfn[maxn],fa[maxn],top[maxn];
int siz[maxn],son[maxn],dep[maxn];
struct edge{int fr,to,nxt;}e[maxn<<1];
struct milk{
  int val,pos;
  bool operator < (const milk &b) const{
    return val<b.val;
  }
}t[maxn];
struct ques{
  int fr,to,c,pos;
  bool operator < (const ques &b) const{
    return c<b.c;
  }
}q[maxn];

namespace Seg{
  #define ls x<<1
  #define rs x<<1|1
  int maxx[maxn<<2];
  void cclear(){
    memset(maxx,-1,sizeof maxx);
  }
  
  void pushup(int x){
    maxx[x]=max(maxx[ls],maxx[rs]);
  }
  
  void update(int x,int l,int r,int pos,int val){
    if(l==r){
      maxx[x]=max(maxx[x],val);
      return;
    }
    int mid=l+r>>1;
    if(pos<=mid) update(ls,l,mid,pos,val);
    else update(rs,mid+1,r,pos,val);
    pushup(x);
  }
  
  int query(int x,int l,int r,int L,int R){
    if(L<=l&&R>=r) return maxx[x];
    int mid=l+r>>1,ans=-1;
    if(L<=mid) ans=max(ans,query(ls,l,mid,L,R));
    if(R>=mid+1) ans=max(ans,query(rs,mid+1,r,L,R));
    return ans;
  }
}

namespace Cut{
  void dfs1(int u,int fat){
    dep[u]=dep[fat]+1;
    siz[u]=1;fa[u]=fat;
    for(int i=head[u];i;i=e[i].nxt){
      int to=e[i].to;
      if(to==fat) continue;
      dfs1(to,u);siz[u]+=siz[to];
      if(siz[son[u]]<siz[to])son[u]=to;
    }
  }
  
  void dfs2(int u,int tp){
    top[u]=tp;dfn[u]=++cnt;
    if(son[u]) dfs2(son[u],tp);
    for(int i=head[u];i;i=e[i].nxt){
      int to=e[i].to;
      if(to==fa[u]||to==son[u]) continue;
      dfs2(to,to);
    }
  }
  
  int getmax(int x,int y){
    int ans=-1;
    while(top[x]!=top[y]){
      if(dep[top[x]]<dep[top[y]]) swap(x,y);
      ans=max(ans,Seg::query(1,1,n,dfn[top[x]],dfn[x]));
      x=fa[top[x]];
    }
    if(dep[x]>dep[y]) swap(x,y);
    ans=max(ans,Seg::query(1,1,n,dfn[x],dfn[y]));
    return ans;
  }
}

void clear(){
  tot=0;cnt=0;Seg::cclear();
  memset(head,0,sizeof head);
  memset(son,0,sizeof son);
  memset(dfn,0,sizeof dfn);
  memset(siz,0,sizeof siz);
  memset(ans,0,sizeof ans);
}

int main(){
  while(scanf("%d%d",&n,&m)!=EOF){
    clear();
    for(int i=1;i<=n;i++) 
      t[i].val=read(),t[i].pos=i;
    for(int i=1,fr,to;i<n;i++){
      fr=read();to=read();
      add(fr,to);add(to,fr);
    }
    Cut::dfs1(1,0);Cut::dfs2(1,1);
    for(int i=1;i<=m;i++)
      q[i].fr=read(),q[i].to=read(),
      q[i].c=read(),q[i].pos=i;
    sort(t+1,t+n+1);sort(q+1,q+m+1);int Now=1;
    for(int i=1;i<=m;i++){
      while(Now<=n&&t[Now].val<=q[i].c){
        Seg::update(1,1,n,dfn[t[Now].pos],t[Now].val);
        Now++;
      }
      ans[q[i].pos]=(Cut::getmax(q[i].fr,q[i].to)==q[i].c);
    }
    for(int i=1;i<=m;i++) printf(ans[i]?"Find\n":"NotFind\n");
  }
  return 0;
}