重链剖分思维量小但相比树上差分码量确实偏大。
原题很清晰不过多叙述。
对路径上的点都做修改,考虑使用重链剖分。
题目特殊的地方在于对父节点也有修改。

对单条路径修改后,未修改且满足题目要求的第一个点是
F
A
[
L
C
A
(
a
,
b
)
]
FA[LCA(a,b)]
FA[LCA(a,b)]。
即上图的2号节点,下下个修改节点即
F
A
[
2
]
=
1
FA[2]=1
FA[2]=1。
即可以确定修改路径:
a
−
>
b
,
F
A
[
L
C
A
(
a
,
b
)
]
−
>
1
a->b,FA[LCA(a,b)]->1
a−>b,FA[LCA(a,b)]−>1
完全平方数的维护可以直接记录质因子的个数的奇偶。(范围在100以内)
100以内质数有25个故直接用整数表示每一位修改时异或即可。
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
//#include
#define guo312 std::ios::sync_with_stdio(false), cin.tie(0), cout.tie(0)
#define ll long long
#define Inf LONG_LONG_MAX
#define inf INT_MAX
#define endl "\n"
#define PI 3.1415926535898
using namespace std;
const int N=2e5+10;
int n,m,q;
vector<int> ve[N];
int id[100];
int lg[N];
bool check(int x){
for(int i=2;i<=sqrt(x);i++){
if(x%i==0) return 0;
}
return 1;
}
void init(){
for(int i=1;i<=n;i++){
lg[i]=lg[i-1]+(1<<lg[i-1]==i);
}
int pos=0;
for(int i=2;i<=100;i++){
if(check(i)){
id[i]=pos++;
}
}
}
//预处理
int dep[N],fa[N][30],son[N],_size[N];
void dfs1(int now,int last){
dep[now]=dep[last]+1; fa[now][0]=last;
_size[now]=1;
for(int i=1;i<=lg[dep[now]];i++){
fa[now][i]=fa[fa[now][i-1]][i-1];
}
int maxn=0;
for(auto it:ve[now]){
if(it==last) continue;
dfs1(it,now);
if(_size[it]>maxn){
maxn=_size[it];
son[now]=it;
}
_size[now]+=_size[it];
}
}
// 重链剖分
int dfn[N],top[N],ti=0;
void dfs2(int now,int topf){
dfn[now]=++ti; top[now]=topf;
if(son[now]==0){
return;
}
dfs2(son[now],topf);
for(auto it:ve[now]){
if(it==fa[now][0]||it==son[now]) continue;
dfs2(it,it);
}
}
struct PW{
int l,r;
ll lazy,val;
}a[N*4];
void pushdown(int id){
a[id<<1].lazy^=a[id].lazy;
a[id<<1|1].lazy^=a[id].lazy;
a[id<<1].val^=a[id].lazy;
a[id<<1|1].val^=a[id].lazy;
a[id].lazy=0;
}
void build(int id,int l,int r){
a[id].l=l,a[id].r=r;
if(l==r){
return ;
}
else{
int mid=l+r>>1;
build(id<<1,l,mid),build(id<<1|1,mid+1,r);
}
}
void modify(int id,int l,int r,ll val){
if(a[id].l>=l&&a[id].r<=r){
a[id].lazy^=val;
a[id].val^=val;
}
else{
pushdown(id);
int mid=a[id].l+a[id].r>>1;
if(r<=mid) modify(id<<1,l,r,val);
else if(l>mid) modify(id<<1|1,l,r,val);
else modify(id<<1,l,r,val),modify(id<<1|1,l,r,val);
}
}
ll query(int id,int x){
if(a[id].l==a[id].r){
return (a[id].val==0);
}
else{
pushdown(id);
int mid=a[id].l+a[id].r>>1;
if(x<=mid) return query(id<<1,x);
else return query(id<<1|1,x);
}
}
// 路径修改
void work(int x,int y,ll val){
while(top[x]!=top[y]){
if(dep[top[x]]<dep[top[y]]){
swap(x,y);
}
modify(1,dfn[top[x]],dfn[x],val);
x=fa[top[x]][0];
}
if(dfn[x]>dfn[y]){
swap(x,y);
}
modify(1,dfn[x],dfn[y],val);
}
// LCA
int LCA(int x,int y){
if(dep[x]<dep[y]) swap(x,y);
while(dep[x]>dep[y]){
x=fa[x][lg[dep[x]-dep[y]]-1];
}
if(x==y) return x;
for(int i=lg[dep[x]]-1;i>=0;i--){
if(fa[x][i]!=fa[y][i]){
x=fa[x][i],y=fa[y][i];
}
}
return fa[x][0];
}
int main(){
guo312;
cin>>n; init();
for(int i=1;i<n;i++){
int x,y; cin>>x>>y;
ve[x].push_back(y);
ve[y].push_back(x);
}
dfs1(1,0); dfs2(1,1); build(1,1,n);
cin>>m;
for(int i=1;i<=m;i++){
int a,b; ll w; cin>>a>>b>>w;
int lca=LCA(a,b);
ll val=w; ll num=0;
for(int j=2;j*j<=w;j++){
int cnt=0;
while(val%j==0){
cnt++,val/=j;
}
if(cnt%2==1){
num+=(1<<id[j]);
}
}
if(val>1){
num+=(1<<id[val]);
}
if(num!=0){
work(a,b,num);
if(lca!=1){
work(fa[lca][0],1,num);
}
}
}
cin>>q;
while(q--){
int pos; cin>>pos;
if(query(1,dfn[pos])) cout<<"YES"<<endl;
else cout<<"NO"<<endl;
}
return 0;
}