传送门:Tsinsen A1486. 树
题意:给你一棵树(n<=1e5),每个点有一个权值和喜欢不喜欢之分,找出一条路径至少包含K个喜欢的点,而且异或和最大
思路:
树分治,同时维护字典树
字典树每个点维护一个喜欢的点数的最大值
时间复杂度:nlogn*30
#include<bits/stdc++.h>
using namespace std;
const int N=101000;
typedef pair<int,int> PI;
struct Edge{
int to,next;
}e[N*2];
int tot,head[N];
void addedge(int from,int to){
e[tot]=(Edge){to,head[from]};
head[from]=tot++;
}
void init(){
memset(head,-1,sizeof(head));
tot=0;
}
int Count,size[N],f[N],root,K,ans,a[N],color[N];
bool Del[N];
void getroot(int u,int fa){
size[u]=1,f[u]=0;
for(int i=head[u];i!=-1;i=e[i].next){
int v=e[i].to;
if(v==fa||Del[v]) continue;
getroot(v,u);
f[u]=max(f[u],size[v]);
size[u]+=size[v];
}
f[u]=max(f[u],Count-size[u]);
if(f[u]<f[root]) root=u;
}
struct Trie{
int ch[N*31][2],val[N*31];
int sz;
void clear(){
sz=1;
memset(ch[0],0,sizeof(ch[0]));
}
void insert(int x,int dep){
int u=0;
for(int i=30;i>=0;i--){
int c=(x&(1<<i))==0 ? 0:1;
if(!ch[u][c]){
memset(ch[sz],0,sizeof(ch[sz]));
val[sz]=0;
ch[u][c]=sz++;
}
u=ch[u][c];
val[u]=max(val[u],dep);
}
}
int find(int x,int dep){//查找的值,查找的深度
int ans=0,u=0;
for(int i=30;i>=0;i--){
int c=(x&(1<<i))==0 ? 0:1;
if(ch[u][c^1]&&val[ ch[u][c^1] ]>=dep)
ans+=(1<<i),u=ch[u][c^1];
else if(ch[u][c]&&val[ ch[u][c] ]>=dep)
u=ch[u][c];
else return -1;
}
return ans;
}
}trie;
vector<PI>tmp;
void getdeep(int u,int pre,int dep,int pre_value,int value){
size[u]=1;
ans=max(ans,trie.find(pre_value^value,K-dep));
tmp.push_back((PI){pre_value,dep});
for(int i=head[u];i!=-1;i=e[i].next){
int v=e[i].to;
if(!Del[v]&&v!=pre)
getdeep(v,u,dep+color[v],pre_value^a[v],value),size[u]+=size[v];
}
}
void work(int u){
Del[u]=true;
trie.clear();
K-=color[u];
if(K<=0) ans=max(ans,a[u]);
trie.insert(0,0);
for(int i=head[u];i!=-1;i=e[i].next){
int v=e[i].to;
if(!Del[v]){
tmp.clear();
getdeep(v,u,color[v],a[v],a[u]);
for(int j=0;j<tmp.size();j++)
trie.insert(tmp[j].first,tmp[j].second);
}
}
//printf("%d %d\n",u,ans);
K+=color[u];
for(int i=head[u];i!=-1;i=e[i].next){
int v=e[i].to;
if(!Del[v]){
Count=f[0]=size[v];
getroot(v,root=0);
work(root);
}
}
}
int main(){
int n,u,v;
scanf("%d%d",&n,&K);
for(int i=1;i<=n;i++) scanf("%d",&color[i]);
for(int i=1;i<=n;i++) scanf("%d",&a[i]);
init();
for(int i=1;i<n;i++){
scanf("%d%d",&u,&v);
addedge(u,v),addedge(v,u);
}
Count=f[0]=n,ans=-1;
memset(Del,false,sizeof(Del));
getroot(1,root=0);
work(root);
printf("%d\n",ans);
return 0;
}