P8201 题解
作者:互联网
题意:
给定一棵树,定义 \(d(u,v)\) 为 \(u\) 和 \(v\) 路径上所有点权的异或,多组询问,给定 \(u,v,k\),问是否存在 \(x\) 使得 \(d(u,x) \bigoplus d(x,v)=k\)。
思路:
观察性质发现,如果存在 \(x\) 不在 \(u,v\) 路径上满足条件,那么 \(u,x\) 路径和 \(v,x\) 路径的第一个交点必然也满足条件,因为第一个交点往后必然一直重合,所以都能够抵消。还可以发现,这个交点必然在 \(u,v\) 路径上,想一想,为什么。
因此,问题等价于在 \(u,v\) 路径上是否存在 \(x\) 使得 \(d(u,x) \bigoplus d(x,v)=k\),由于 \(d(u,x) \bigoplus d(x,v)=d(u,v)\bigoplus w_x\),转化为在 \(u,v\) 路径上是否存在 \(x\) 使得 \(d(u,v)\bigoplus w_x=k\),左右同时异或 \(d(u,v)\) 得到 \(w_x=d(u,v)\bigoplus k\),由于右式是个常数,设为 \(y\),最终转化为判断一条路径上是否存在点权为 \(y\) 的点。
与其维护是否存在,不如直接维护个数,定义 \(f(u,v,w)\) 表示 \(u,v\) 路径上 \(x\) 的出现次数。
由于出现次数具有可减性,所以 \(f(u,v,w)=f(u,1,w)+f(v,1,w)-f(lca(u,v),1,w)-f(father_{lca(u,v)},1,w)\),把 \(f(u,v,w)\) 这一个询问拆成四个询问处理,转化为任意 \(u,w\) 求 \(f(u,1,w)\)。
这很明显是个数据结构问题,下面给出两种做法:
- 考虑主席树,由于加入 \(x\) 这个点相当于是在其父亲的版本上加入有关 \(w_x\) 的信息,那么可以在合理的时间内建出每个点的主席树,直接求解即可,代码难度稍大。
- 考虑离线下来,全局桶维护,离开这个点时删除这个点在桶中的贡献,那么对于每一个点都能得到一个维护它到根路径信息的桶,但是这个点的顺序是 dfn 序,对询问的点并不连续,所以将所有拆开的询问按 dfn 排序,那么可以得到答案的总是询问的一个前缀,单指针扫一遍即可,实现细节比较多。
代码:
给出第二种做法的代码:
#include<bits/stdc++.h>
using namespace std;
#define int long long
int n,m,id,dfn[(int)(5e5+10)],w[(int)(5e5+10)],f[35][(int)(5e5+10)];
int res[(int)(5e5+10)],dep[(int)(5e5+10)],p[(int)(5e5+10)],d[(int)(5e5+10)];
vector<int>edge[(int)(5e5+10)];
void dfs(int u,int fa)
{
dfn[u]=++id;f[0][u]=fa;
dep[u]=dep[fa]+1;p[u]^=p[fa];
for(int i=1;i<=20;i++)
{
f[i][u]=f[i-1][f[i-1][u]];
}
for(int i=0;i<edge[u].size();i++)
{
int v=edge[u][i];
if(v==fa) continue;
dfs(v,u);
}
}
int lca(int x,int y)
{
if(dep[x]<dep[y]) swap(x,y);
while(dep[x]>dep[y])
{
x=f[d[dep[x]-dep[y]]-1][x];
}
if(x==y) return x;
for(int i=d[dep[x]]-1;i>=0;i--)
{
if(f[i][x]!=f[i][y]) x=f[i][x],y=f[i][y];
}
return f[0][x];
}
struct node
{
int id,type,u,val,dfn,from,ans;
}a[(int)(2e6+10)],b[(int)(2e6+10)];
bool cmp(node a,node b)
{
return a.dfn<b.dfn;
}
map<int,int>mp;
int now=1,top=0;
void dfs1(int u,int fa)
{
mp[w[u]]++;
while(a[now].u==u&&now<=top)
{
a[now].ans=mp[a[now].val];
now++;
}
for(int i=0;i<edge[u].size();i++)
{
int v=edge[u][i];
if(v==fa) continue;
dfs1(v,u);
}
mp[w[u]]--;
}
signed main()
{
cin>>n>>m;
for(int i=1;i<=n;i++) scanf("%lld",&w[i]),p[i]=w[i];
for(int i=1;i<n;i++)
{
int u,v;scanf("%lld %lld",&u,&v);
edge[u].push_back(v);
edge[v].push_back(u);
}
for(int i=1;i<=n;i++)
{
d[i]=d[i-1]+(1<<d[i-1]==i);
}
dfs(1,0);
for(int i=1;i<=m;i++)
{
int u,v,k;scanf("%lld %lld %lld",&u,&v,&k);
int t=lca(u,v);
if(t==u||t==v)
{
if(v==t)
{
a[++top]=(node){top,1,u,p[u]^p[f[0][t]]^k,dfn[u],i,0};
if(t!=1) a[++top]=(node){top,-1,f[0][t],p[u]^p[f[0][t]]^k,dfn[f[0][t]],i,0};
}
else
{
a[++top]=(node){top,1,v,p[v]^p[f[0][t]]^k,dfn[v],i,0};
if(t!=1) a[++top]=(node){top,-1,f[0][t],p[v]^p[f[0][t]]^k,dfn[f[0][t]],i,0};
}
}
else
{
a[++top]=(node){top,1,u,p[u]^p[v]^w[t]^k,dfn[u],i,0};
a[++top]=(node){top,1,v,p[u]^p[v]^w[t]^k,dfn[v],i,0};
a[++top]=(node){top,-1,t,p[u]^p[v]^w[t]^k,dfn[t],i,0};
if(t!=1) a[++top]=(node){top,-1,f[0][t],p[u]^p[v]^w[t]^k,dfn[f[0][t]],i,0};
}
}
sort(a+1,a+1+top,cmp);
dfs1(1,0);
for(int i=1;i<=top;i++)
{
// cout<<a[i].u<<"\n";
b[a[i].id]=a[i];
}
for(int i=1;i<=top;i++)
{
res[b[i].from]+=b[i].type*b[i].ans;
}
for(int i=1;i<=m;i++)
{
// assert(res[i]>=0);
if(res[i]) puts("Yes");
else puts("No");
}
system("pause > null");
}
标签:10,int,题解,路径,dep,bigoplus,5e5,P8201 来源: https://www.cnblogs.com/blog-WHY/p/16220719.html