分析
一眼树上启发式合并。
定义 \(x_i\) 为节点 \(i\) 在序列 \(p\) 中的下标。则问题转化为:对于每组 \(l,r,k\),询问以 \(k\) 为根的子树中是否有一个以上的节点,满足 \(l \le x_j \le r\)。
使用 set 存以 \(i\) 为根的子树中 \(x_j\) 的有序排列。则对于每个 \(k=i\) 的询问,去合并之后的 set 中二分查找即可。树上启发式合并的话套版子就行了,只是多加了一个更新询问答案的过程而已。
注:模板题可以参照这道。但该模板题难度评级显然有问题。
代码
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define re register
#define il inline
#define PII pair<int,pair<int,int>>
#define x first
#define y second
const int N=1e5+10;
int n,q;
int ne[N<<1],e[N<<1],h[N],idx;
struct node{
set<int> st;
vector<PII> Q;
il int size(){return st.size();}
}sub[N];int x[N],id[N],cnt;
int ans[N];
il void add(int a,int b){ne[++idx]=h[a],e[idx]=b,h[a]=idx;}
il void dfs(int now,int fa){
int mson=-1,msiz=0;
id[now]=++cnt;
for(re int i=h[now];i;i=ne[i]){
int j=e[i];if(j==fa) continue;
dfs(j,now);
if(sub[id[j]].size()>msiz) msiz=sub[id[j]].size(),mson=j;
}
if(mson!=-1) id[now]=id[mson];
for(re int i=h[now];i;i=ne[i]){
int j=e[i];if(j==fa||j==mson) continue;
for(auto s:sub[id[j]].st) sub[id[now]].st.insert(s);
sub[id[j]].st.clear();
}
sub[id[now]].st.insert(x[now]);
for(auto i:sub[now].Q){
auto j=sub[id[now]].st.lower_bound(i.y.x);
ans[i.x]=(j!=sub[id[now]].st.end()&&(*j)<=i.y.y);
}
return ;
}
il void solve(){
cin>>n>>q;
for(re int i=1;i<=n;++i) h[i]=ans[i]=x[i]=id[i]=0,sub[i].Q.clear(),sub[i].st.clear();
idx=cnt=0;
for(re int i=1,a,b;i<n;++i) cin>>a>>b,add(a,b),add(b,a);
for(re int i=1,s;i<=n;++i) cin>>s,x[s]=i;
for(re int i=1,l,r,x;i<=q;++i) cin>>l>>r>>x,sub[x].Q.push_back({i,{l,r}});
dfs(1,0);
for(re int i=1;i<=q;++i)
if(ans[i]) cout<<"YES\n";
else cout<<"NO\n";
return ;
}
signed main(){
int t;cin>>t;while(t--)
solve();
return 0;
}
标签:Unusual,sub,int,题解,CF1899G,st,re,now,id
From: https://www.cnblogs.com/harmisyz/p/18058639