简要题意:
给你一棵有根树,每个点uuu有正数权值aua_uau,定义一个点uuu的权值fuf_ufu为其子树中点的aaa之和。
对于两个点u,vu,vu,v,我们称uuu能到达vvv当且仅当fuf_ufu与该路径上fff的最大值和最小值都不相等。
对于每个点uuu,请你求出所有它能达到的所有点的fff值按位或的结果。
题解:
如果是异或可能会好做一点。
由于是按位或而不是异或,没有逆运算,我们能够利用的只有交换律和结合律。
首先注意到由于所有aua_uau都是正数,也就意味着任何一个点到根的路径上的fff单调递增。
容易注意到一个点不能往子树走,因为这样它一定是路径上最大值。
那么任何具有祖先后代关系的节点都不能互相到达(这什么破规定),那么考虑两个没有祖先后代关系的点。
容易注意到LCALCALCA就是路径上权值最大的点,则两个没有祖先后代关系的点u,vu,vu,v,uuu能到达vvv当且仅当fu>fvf_u>f_vfu>fv,即fuf_ufu不是路径上最小值。
剩下的就和 PKUWC 2018 Minimax 的线段树合并套路一样了。
建立权值线段树,从左到右合并的同时维护一下当前位或额结果。
注意到我们需要在线段树叶子节点维护点的集合并且需要支持打标记和快速合并,采用平衡树或者可并堆的策略合并即可。
全场只有我一个人写的线段树合并。。。
然而跑得比几乎所有的树状数组都快。
时间复杂度上界O(nlogn)O(n\log n)O(nlogn)不满,下界好像很低但不是很清楚,由于常数问题还是比不过一些树状数组。
代码:
#include<bits/stdc++.h>
#define ll long long
#define re register
#define cs const
namespace IO{
inline char gc(){
static cs int Rlen=1<<22|1;
static char buf[Rlen],*p1,*p2;
return (p1==p2)&&(p2=(p1=buf)+fread(buf,1,Rlen,stdin),p1==p2)?EOF:*p1++;
}template<typename T>inline T get(){
char c;T num;
while(!isdigit(c=gc()));num=c^48;
while(isdigit(c=gc()))num=(num+(num<<2)<<1)+(c^48);
return num;
}inline int gi(){return get<int>();}
}
using namespace IO;
using std::cerr;
using std::cout;
cs int N=4e5+7;
int n,c,m;
int g[N],f[N],rk[N],val[N];
namespace SBT{
cs int N=4e5+7;
int lc[N],rc[N],tag[N],ht[N];
inline void init(int n){std::fill(ht+1,ht+n+1,1);}
inline void push(int u,int vl){tag[u]|=vl;}
inline void pushdown(int u){
if(tag[u]){
if(lc[u])tag[lc[u]]|=tag[u];
if(rc[u])tag[rc[u]]|=tag[u];
g[u]|=tag[u],tag[u]=0;
}
}
inline int merge(int u,int v){
if(!u||!v)return u|v;
if(ht[u]>ht[v])std::swap(u,v);
pushdown(u);rc[u]=merge(rc[u],v);
if(ht[rc[u]]>ht[lc[u]])std::swap(lc[u],rc[u]);
ht[u]=ht[rc[u]]+1;return u;
}
inline void pushall(int u){pushdown(u);if(lc[u])pushall(lc[u]);if(rc[u])pushall(rc[u]);}
}
namespace SGT{
cs int N=::N*20;
int lc[N],rc[N],tag[N],vl[N],rt[N],dl[N],tp,tot;
inline int newnode(){
int u=tp?dl[tp--]:++tot;
lc[u]=rc[u]=0,tag[u]=vl[u]=rt[u]=0;
return u;
}
inline void push(int u,int vl){tag[u]|=vl;}
inline void pushdown(int u){
if(tag[u]){
if(lc[u])tag[lc[u]]|=tag[u];
if(rc[u])tag[rc[u]]|=tag[u];
tag[u]=0;
}
}
inline void pushup(int u){vl[u]=vl[lc[u]]|vl[rc[u]];}
inline void ins(int &u,int l,int r,int p,int ps){
if(!u)u=newnode();
if(l==r){
vl[u]=val[l];
rt[u]=SBT::merge(rt[u],ps);
return ;
}int mid=l+r>>1;pushdown(u);
(p<=mid)?ins(lc[u],l,mid,p,ps):ins(rc[u],mid+1,r,p,ps);
pushup(u);
}
int pre_u,pre_v;
inline int merge(int u,int v,int l,int r){
if(!u&&!v)return 0;
if(!u&&v){
push(v,pre_u);
pre_v|=vl[v];
return v;
}
if(!v&&u){
push(u,pre_v);
pre_u|=vl[u];
return u;
}
if(l==r){
SBT::push(rt[u],tag[u]|pre_v);
SBT::push(rt[v],tag[v]|pre_u);
rt[u]=SBT::merge(rt[u],rt[v]);
tag[u]=tag[v]=0;
pre_u|=val[l],pre_v|=val[l];
dl[++tp]=v;return u;
}int mid=l+r>>1;
pushdown(u),pushdown(v);
lc[u]=merge(lc[u],lc[v],l,mid);
rc[u]=merge(rc[u],rc[v],mid+1,r);
pushup(u);dl[++tp]=v;return u;
}
inline void pushall(int u,int l,int r){
if(!u)return ;
if(l==r){
SBT::push(rt[u],tag[u]);
SBT::pushall(rt[u]);
return ;
}int mid=l+r>>1;pushdown(u);
pushall(lc[u],l,mid);pushall(rc[u],mid+1,r);
}
}
int el[N],nxt[N<<1|1],to[N<<1|1],ec;
inline void adde(int u,int v){
nxt[++ec]=el[u],el[u]=ec,to[ec]=v;
nxt[++ec]=el[v],el[v]=ec,to[ec]=u;
}
void pre_dfs(int u,int p){
for(int re e=el[u],v;e;e=nxt[e])
if((v=to[e])!=p)pre_dfs(v,u),f[u]+=f[v];
}
int rt[N];
void dfs(int u,int p){
for(int re e=el[u],v;e;e=nxt[e])
if((v=to[e])!=p){
dfs(v,u);SGT::pre_u=SGT::pre_v=0;
rt[u]=SGT::merge(rt[u],rt[v],1,m);
}
SGT::ins(rt[u],1,m,rk[u],u);
}
signed main(){
#ifdef zxyoi
freopen("forever.in","r",stdin);
#else
#ifndef ONLINE_JUDGE
freopen("forever.in","r",stdin);freopen("forever.out","w",stdout);
#else
int size=200<<20;
__asm__ ("movq %0,%%rsp\n"::"r"((char*)malloc(size)+size));
#endif
#endif
n=gi(),c=gi();
for(int re i=1;i<n;++i)adde(gi(),gi());
for(int re i=1;i<=n;++i)f[i]=gi();pre_dfs(c,0);
for(int re i=1;i<=n;++i)val[i]=f[i];
std::sort(val+1,val+n+1);m=std::unique(val+1,val+n+1)-val-1;
for(int re i=1;i<=n;++i)rk[i]=std::lower_bound(val+1,val+m+1,f[i])-val;
SBT::init(n);dfs(c,0);SGT::pushall(rt[c],1,m);
for(int re i=1;i<=n;++i)cout<<g[i]<<" ";
exit(0);
}