P8201题解

· · 个人记录

思路

设任意一个点 udis_{u,x} \oplus dis_{u,y} = k

问题转化为,x \rightarrow y 的链上是否有一个点,权值是 k \oplus s_x \oplus s_y \oplus w_{lca_{x,y}} ,也就是统计 x \rightarrow y 这条链上权值为 k \oplus s_x \oplus s_y \oplus w_{lca_{x,y}} 的点的数量(注意这个权值仅仅是当前询问对应的!
对于每一组这样的 x,y ,设 z_i 表示从 1i 点权值为 k \oplus s_x \oplus s_y \oplus w_{lca_{x,y}} 的数量 (注意这个 z_i 仅仅是当前询问对应的 z_i),答案就是 z_x + z_y - z_{lca_{x,y}} - z_{lca_{x,y}.father}。把所有询问离线一下,将 x,y,lca_{x,y},lca_{x,y}.father 在树上做一下标记,dfs 的时候集中处理
dfs 具体如下:
dfs 前打标记部分:在树上指定部分标上 +1 或 -1,代表这次询问要加上还是减去这个点的贡献。
dfs 部分:设当前 dfs 到了点 u,那么将该点权值对应的 z_u 乘上该点标记加到对应的询问里去。

最后看每个询问的值是否大于 0 就行了

注意:

### 代码: ```cpp #include <bits/stdc++.h> using namespace std; namespace Main { const int maxn=5e5+5; int n,m; int w[maxn]; int head[maxn]; struct EDGE { int to,nxt; }edge[maxn<<1]; int cnt; inline void add(int u,int to) { edge[++cnt].to=to; edge[cnt].nxt=head[u]; head[u]=cnt; } int fa[20][maxn]; int dep[maxn]; int s[maxn]; void dfs(int u,int _fa) { s[u]=s[_fa]^w[u]; dep[u]=dep[_fa]+1; fa[0][u]=_fa; for(int i=1;i<=19;i++) { fa[i][u]=fa[i-1][fa[i-1][u]]; } for(int i=head[u];i;i=edge[i].nxt) { int to=edge[i].to; if(to==_fa)continue; dfs(to,u); } } inline int lca(int x,int y) { if(dep[x]<dep[y])swap(x,y); for(int i=19;i>=0;i--) { if(dep[fa[i][x]]>=dep[y]) { x=fa[i][x]; } } if(x==y)return x; for(int i=19;i>=0;i--) { if(fa[i][x]!=fa[i][y]) { x=fa[i][x]; y=fa[i][y]; } } return fa[0][x]; } int t[maxn]; vector<pair<int,int> > tag[maxn]; int tot[10000005]; int count[maxn]; void dfs2(int u,int _fa) { tot[w[u]]++; for(int i=0;i<tag[u].size();i++) { int id=tag[u][i].first; int w=tag[u][i].second; count[id]+=w*tot[t[id]]; } for(int i=head[u];i;i=edge[i].nxt) { int to=edge[i].to; if(to==_fa)continue; dfs2(to,u); } tot[w[u]]--;//退出当前链,记得清除标记 } void main() { scanf("%d%d",&n,&m); for(int i=1;i<=n;i++) { scanf("%d",&w[i]); } for(int i=1;i<n;i++) { int x,y; scanf("%d%d",&x,&y); add(x,y); add(y,x); } dfs(1,0); for(int i=1;i<=m;i++) { int a,b,k; scanf("%d%d%d",&a,&b,&k); int _lca=lca(a,b); t[i]=k^s[a]^s[b]^w[_lca]; if(t[i]>1e7)continue; tag[a].emplace_back(make_pair(i,1)); tag[b].emplace_back(make_pair(i,1)); tag[_lca].emplace_back(make_pair(i,-1)); tag[fa[0][_lca]].emplace_back(make_pair(i,-1)); } dfs2(1,0); for(int i=1;i<=m;i++) { if(count[i]>0) { printf("Yes\n"); } else { printf("No\n"); } } } } int main() { Main::main(); return 0; } ``` ### 参考博客 [一扶苏一的博客](https://www.luogu.com.cn/blog/fusu2333/solution-p8201)