peiwenjun's blog 没有知识的荒原

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;
}

posted on 2022-05-08 16:39  peiwenjun  阅读(7)  评论(0)    收藏  举报

导航