P5354 [Ynoi2017] 由乃的 OJ 题解
题目描述
给定一棵 \(n\) 个点的树,每个点有操作符号 \(opt_u\) 和权值 \(w_u\) 。
\(x\) 经过这个点后会变成 \(x\ opt_u\ w_u\) ,其中 \(opt_u\) 是按位与,按位或,按位异或三种之一。
接下来 \(m\) 次操作:
- 询问走过 \(u\to v\) 的路径,以 \(\le w\) 的初始值出发,得到的最大权值。
- 单点修改 \(opt_u,w_u\) 。
数据范围
- \(0\le n,m\le 10^5\) 。
- \(opt_u\in\{1,2,3\}\) ,分别表示
&,|,^, \(0\le w\lt 2^{64}\) 。
时间限制 \(\texttt{250ms}\) ,空间限制 \(\texttt{128MB}\) 。
分析
P2114的树上带修版本。
树上问题转序列问题,果断树链剖分。
由于每一位独立,我们只需维护 \(0\) 和 \(2^k-1\) 经过一个区间会变成什么,分别记为 \(f_0,f_1\) 。
由于从下往上和从下往上的路径效果不同,所以还要维护从左往右和从右往左的操作,分别记为 \(g_0,g_1\) 。
本题唯一的难点就是 pushup 。
以从左往右,从 \(0\) 出发为例,如果它想变成\(1\),有两种情况:
- 经过左半边后变成\(0\),然后通过右半边变成\(1\)。
- 经过左半边后变成\(1\),然后通过右半边变成\(1\)。
现在要把\(64\)位压在一起,那么可以写出代码:
res.f0=((~p.f0)&q.f0)|(p.f0&q.f1);
其余 \(3\) 项同理。
时间复杂度 \(\mathcal O(n\log^2n+nk)\) 。
#include<bits/stdc++.h>
#define ull unsigned long long
using namespace std;
const int maxn=100005;
const ull all=-1;
int k,n,q,u,v,cnt,tot;
int opt[maxn];
ull w[maxn];
int head[maxn],to[2*maxn],nxt[2*maxn];
int d[maxn],fa[maxn],sz[maxn],son[maxn];
int id[maxn],dfn[maxn],top[maxn];
struct node
{
int l,r;
ull f0,f1,g0,g1;
void init(int opt,ull w)
{
if(opt==1) f0=g0=0,f1=g1=w;
if(opt==2) f0=g0=w,f1=g1=all;
if(opt==3) f0=g0=w,f1=g1=all^w;
}
ull calc(ull w)
{
ull res=0;
for(int i=k-1;i>=0;i--)
{
ull now=1ll<<i;
if(f0>>i&1) res|=now;
else if((f1>>i&1)&&w>=now) w-=now,res|=now;
}
return res;
}
}f[4*maxn];
ull read()
{
ull q=0;char ch=getchar();
while(ch<'0'||ch>'9') ch=getchar();
while(ch>='0'&&ch<='9') q=10*q+ch-'0',ch=getchar();
return q;
}
void addedge(int u,int v)
{
nxt[++tot]=head[u],to[tot]=v,head[u]=tot;
}
void dfs1(int u,int father)
{
for(int i=head[u];i!=0;i=nxt[i])
{
int v=to[i];
if(v==father) continue;
d[v]=d[u]+1,fa[v]=u;
dfs1(v,u);
sz[u]+=sz[v];
if(sz[v]>=sz[son[u]]) son[u]=v;
}
sz[u]++;
}
void dfs2(int u,int topf)
{
dfn[u]=++cnt,id[cnt]=u,top[u]=topf;
if(son[u]) dfs2(son[u],topf);
for(int i=head[u];i!=0;i=nxt[i])
{
int v=to[i];
if(v==fa[u]||v==son[u]) continue;
dfs2(v,v);
}
}
node merge(node p,node q)
{
static node res;
res.l=p.l,res.r=q.r;
res.f0=((~p.f0)&q.f0)|(p.f0&q.f1);
res.f1=((~p.f1)&q.f0)|(p.f1&q.f1);
res.g0=((~q.g0)&p.g0)|(q.g0&p.g1);
res.g1=((~q.g1)&p.g0)|(q.g1&p.g1);
return res;
}
void pushup(int p)
{
f[p]=merge(f[2*p],f[2*p+1]);
}
void build(int p,int l,int r)
{
f[p].l=l,f[p].r=r;
if(l==r) return f[p].init(opt[id[l]],w[id[l]]);
int mid=(l+r)/2;
build(2*p,l,mid);
build(2*p+1,mid+1,r);
pushup(p);
}
void modify(int p,int pos,int opt,ull w)
{
if(f[p].l==f[p].r) return f[p].init(opt,w);
int mid=(f[p].l+f[p].r)/2;
if(pos<=mid) modify(2*p,pos,opt,w);
else modify(2*p+1,pos,opt,w);
pushup(p);
}
node query(int p,int l,int r)
{
if(l<=f[p].l&&f[p].r<=r) return f[p];
int mid=(f[p].l+f[p].r)/2;
if(r<=mid) return query(2*p,l,r);
if(l>=mid+1) return query(2*p+1,l,r);
return merge(query(2*p,l,r),query(2*p+1,l,r));
}
ull querychain(int u,int v,ull w)
{
static node p,q;
p.l=p.r=0,p.init(3,0);
q.l=q.r=0,q.init(3,0);
int rev=0;
while(top[u]!=top[v])
{
if(d[top[u]]<d[top[v]]) rev^=1,swap(u,v);
if(rev==0) p=merge(query(1,dfn[top[u]],dfn[u]),p);
else q=merge(query(1,dfn[top[u]],dfn[u]),q);
u=fa[top[u]];
}
if(d[u]>d[v]) swap(u,v),rev^=1;
if(rev==0) q=merge(query(1,dfn[u],dfn[v]),q);
else p=merge(query(1,dfn[u],dfn[v]),p);
swap(p.f0,p.g0),swap(p.f1,p.g1);
return merge(p,q).calc(w);
}
int main()
{
n=read(),q=read(),k=read();
for(int i=1;i<=n;i++) opt[i]=read(),w[i]=read();
for(int i=1;i<=n-1;i++)
{
u=read(),v=read();
addedge(u,v),addedge(v,u);
}
d[1]=1,dfs1(1,0),dfs2(1,1);
build(1,1,n);
while(q--)
{
int opt=read(),u=read(),v=read();
if(opt==1) printf("%llu\n",querychain(u,v,read()));
else modify(1,dfn[u],v,read());
}
return 0;
}
本文来自博客园,作者:peiwenjun,转载请注明原文链接:https://www.cnblogs.com/peiwenjun/p/16246005.html
浙公网安备 33010602011771号