首先考虑问题的简化版
存在下面两个操作
- 询问 [ l , r ] [l,r] [l,r]区间与非的值即 a l NAND a l + 1 NAND … NAND a r a_l \text{NAND} a_{l+1} \text{NAND}\dots \text{NAND} a_r alNANDal+1NAND…NANDar
- 单线修改 p , x p,x p,x即 a p = x a_p=x ap=x
这是一道去年校赛题最近才发现区间与非的板子题
首先直觉告诉我们要用线段树维护此操作,但是区间与非没有结合律,这样的信息线段树不能直接维护,不过位运算具有独立性,我们可以一位一位去考虑。
考虑用线段树每个节点维护 L [ 0 / 1 ] , R [ 0 / 1 ] \text{L}[0/1],\text{R}[0/1] L[0/1],R[0/1]
L
[
0
]
\text{L}[0]
L[0]表示刚开是
0
0
0,然后从左向右经过此区间是最终的数(此节点维护的区间)
L
[
1
]
\text{L}[1]
L[1]表示刚开是
1
1
1,然后从左向右经过此区间是最终的数
R
[
0
]
\text{R}[0]
R[0]表示刚开是
0
0
0,然后从右向左经过此区间是最终的数
R
[
1
]
\text{R}[1]
R[1]表示刚开是
1
1
1,然后从右向左经过此区间是最终的数
然后只需要维护32棵线段树(按位),就可以区间询问了。
2908. 又是nand
而此题就是套了个树链剖分,并且注意询问的时候有的区间是从左向右,有的区间是从右向左(yy一下树剖的样子即可)
#include<bits/stdc++.h>
using namespace std;
using u32=unsigned int;
using pii=pair<int,int>;
constexpr int N=100010;
int n,m,bit;
u32 a[N];
int h[N],e[2*N],ne[2*N],idx;
int sz[N],son[N],fa[N],dep[N];
int dfn[N],top[N],id[N],timestamp;
void add(int a,int b){e[idx]=b,ne[idx]=h[a],h[a]=idx++;}
struct Segment
{
struct node
{
int l,r;
bool L[2],R[2];
}tree[N<<2];
void pushup(int u)
{
tree[u].L[0]=tree[u<<1|1].L[tree[u<<1].L[0]];
tree[u].L[1]=tree[u<<1|1].L[tree[u<<1].L[1]];
tree[u].R[0]=tree[u<<1].R[tree[u<<1|1].R[0]];
tree[u].R[1]=tree[u<<1].R[tree[u<<1|1].R[1]];
}
void build(int u,int l,int r,int k)
{
tree[u].l=l,tree[u].r=r;
if(l==r)
{
tree[u].L[0]=tree[u].R[0]=1;
tree[u].L[1]=tree[u].R[1]=!(a[id[l]]>>k&1);
return;
}
int mid=l+r>>1;
build(u<<1,l,mid,k);build(u<<1|1,mid+1,r,k);
pushup(u);
}
void modify(int u,int pos,bool x)
{
if(tree[u].l==tree[u].r)
{
tree[u].L[0]=tree[u].R[0]=1;
tree[u].L[1]=tree[u].R[1]=(!x);
return;
}
int mid=tree[u].l+tree[u].r>>1;
if(pos<=mid)
modify(u<<1,pos,x);
else
modify(u<<1|1,pos,x);
pushup(u);
}
bool queryL(int u,int l,int r,bool c)
{
if(l<=tree[u].l&&tree[u].r<=r) return tree[u].L[c];
int mid=tree[u].l+tree[u].r>>1;
if(r<=mid)
return queryL(u<<1,l,r,c);
else if(l>mid)
return queryL(u<<1|1,l,r,c);
else
return queryL(u<<1|1,l,r,queryL(u<<1,l,r,c));
}
bool queryR(int u,int l,int r,bool c)
{
if(l<=tree[u].l&&tree[u].r<=r) return tree[u].R[c];
int mid=tree[u].l+tree[u].r>>1;
if(r<=mid)
return queryR(u<<1,l,r,c);
else if(l>mid)
return queryR(u<<1|1,l,r,c);
else
return queryR(u<<1,l,r,queryR(u<<1|1,l,r,c));
}
}T[33];
//==============================================================
void dfs1(int u)
{
dep[u]=dep[fa[u]]+1;
sz[u]=1;
for(int i=h[u];i!=-1;i=ne[i])
{
int v=e[i];
if(v==fa[u]) continue;
fa[v]=u;
dfs1(v);
sz[u]+=sz[v];
if(sz[son[u]]<sz[v]) son[u]=v;
}
}
void dfs2(int u,int t)
{
dfn[u]=++timestamp;
id[timestamp]=u;
top[u]=t;
if(son[u]) dfs2(son[u],t);
for(int i=h[u];i!=-1;i=ne[i])
{
int v=e[i];
if(v==fa[u]||v==son[u]) continue;
dfs2(v,v);
}
}
//==============================================================
void update(int u,u32 x)
{
for(int k=0;k<bit;k++)
T[k].modify(1,dfn[u],x>>k&1);
}
u32 ask(int u,int v)
{
u32 ans=0;
vector<pii> ql,qr;
while(top[u]!=top[v])
{
if(dep[top[u]]>=dep[top[v]])// debug 1h
{
qr.push_back({dfn[top[u]],dfn[u]});
u=fa[top[u]];
}
else
{
ql.push_back({dfn[top[v]],dfn[v]});
v=fa[top[v]];
}
}
if(dep[u]>=dep[v])
qr.push_back({dfn[v],dfn[u]});
else
ql.push_back({dfn[u],dfn[v]});
reverse(ql.begin(),ql.end());
for(pii t:qr)
{
int l=t.first,r=t.second;
for(int k=0;k<bit;k++)
ans=ans-(ans&(1<<k))+(T[k].queryR(1,l,r,ans>>k&1)<<k);
}
for(pii t:ql)
{
int l=t.first,r=t.second;
for(int k=0;k<bit;k++)
ans=ans-(ans&(1<<k))+(T[k].queryL(1,l,r,ans>>k&1)<<k);
}
return ans;
}
int main()
{
ios::sync_with_stdio(false);cin.tie(nullptr);cout.tie(nullptr);
memset(h,-1,sizeof h);
cin>>n>>m>>bit;
for(int i=1;i<=n;i++) cin>>a[i];
for(int i=1;i<n;i++)
{
int u,v;
cin>>u>>v;
add(u,v),add(v,u);
}
dfs1(1);
dfs2(1,1);
for(int k=0;k<bit;k++)
T[k].build(1,1,n,k);
while(m--)
{
char op[10];u32 a,b;
cin>>op>>a>>b;
if(*op=='R')
update(a,b);
else
cout<<ask(a,b)<<'\n';
}
return 0;
}
终于补完了区间NAND的板子
要加油哦~