观察nand这个运算,发现它有交换律但是没有结合律,所以就不要考虑各种差分或者分段计算合并的方法,而且得按顺序维护。
首先可以想到树链剖分,因为有顺序,所以线段树区间上要维护从
l
l
到的运算结果和从
r
r
到的运算结果,而且对于运算结果还与进来的初值有关,发现每一位是独立的,我们要对每一位维护初值是
0/1
0
/
1
,运算顺序是
l→r/r→l
l
→
r
/
r
→
l
的结果。复杂度
O(nlog3n)
O
(
n
log
3
n
)
。
还可以用位运算优化,所有位一起考虑,直接维护初值为
0/2k−1
0
/
2
k
−
1
的运算结果,计算通过这个区间的结果时候把初值的
0
0
位和位分别提取出来即可,复杂度
O(nlog2n)
O
(
n
log
2
n
)
。
代码:
#include<iostream>
#include<cstring>
#include<cstdio>
#define N 100010
#define uint unsigned int
#define mid (l+r>>1)
#define fs first
#define sc second
using namespace std;
const uint R=4294967295;
int n,m,k,dep[N],fa[N],sz[N],hs[N],dfn[N],ed[N],fd[N],hd[N],tim;
uint a[N],sk;
pair<int,int> stx[N],sty[N];
uint read()
{
uint x=0,f=1;char ch=getchar();
for(;ch<'0'||ch>'9';ch=getchar()) if(ch=='-') f=-1;
for(;ch>='0'&&ch<='9';ch=getchar()) x=x*10+ch-'0';
return x*f;
}
struct edge
{
int t;
edge *next;
}*con[N];
void ins(int x,int y)
{
edge *p=new edge;
p->t=y;
p->next=con[x];
con[x]=p;
}
void dfs1(int v)
{
sz[v]=1;dep[v]=dep[fa[v]]+1;
for(edge *p=con[v];p;p=p->next)
if(p->t!=fa[v])
{
fa[p->t]=v;
dfs1(p->t);
sz[v]+=sz[p->t];
if(sz[p->t]>sz[hs[v]]) hs[v]=p->t;
}
}
void dfs2(int v)
{
dfn[v]=++tim;fd[tim]=v;
if(hs[fa[v]]!=v) hd[v]=v;else hd[v]=hd[fa[v]];
if(hs[v]) dfs2(hs[v]);
for(edge *p=con[v];p;p=p->next)
if(p->t!=fa[v]&&p->t!=hs[v]) dfs2(p->t);
ed[v]=tim;
}
struct tree
{
uint d[2][2];
tree *s[2];
tree(){s[0]=s[1]=0;}
void init(uint x)
{
d[0][0]=d[1][0]=R;
d[0][1]=d[1][1]=R^(R&x);
}
uint run(uint x,int b)
{
return (x&d[b][1])|((R^x)&d[b][0]);
}
void update()
{
for(int t=0;t<2;t++)
for(int b=0;b<2;b++)
d[b][t]=s[b^1]->run(s[b]->d[b][t],b);
}
void build(int l,int r)
{
if(l==r) {init(a[fd[l]]);return ;}
(s[0]=new tree)->build(l,mid);
(s[1]=new tree)->build(mid+1,r);
update();
}
void mdf(int l,int r,int x,uint y)
{
if(l==r) {init(y);return ;}
int b=x>mid;if(b) l=mid+1;else r=mid;
s[b]->mdf(l,r,x,y);
update();
}
uint qry(int l,int r,int lx,int rx,uint x,int b)
{
lx=max(l,lx);rx=min(r,rx);
if(l==lx&&r==rx) return run(x,b);
if(rx<=mid) return s[0]->qry(l,mid,lx,rx,x,b);
if(lx>mid) return s[1]->qry(mid+1,r,lx,rx,x,b);
uint tmp=s[b]->qry(b?mid+1:l,b?r:mid,lx,rx,x,b);
return s[b^1]->qry(b?l:mid+1,b?mid:r,lx,rx,tmp,b);
}
}*xtr;
uint query(int x,int y)
{
int tx=0,ty=0;
while(hd[x]!=hd[y])
{
if(dep[hd[x]]>=dep[hd[y]])
{
stx[++tx]=make_pair(hd[x],x);
x=fa[hd[x]];
}
else
{
sty[++ty]=make_pair(hd[y],y);
y=fa[hd[y]];
}
}
if(dep[x]>=dep[y]) stx[++tx]=make_pair(y,x);
else sty[++ty]=make_pair(x,y);
uint re=0;
for(int i=1;i<=tx;i++)
re=xtr->qry(1,n,dfn[stx[i].fs],dfn[stx[i].sc],re,1);
for(int i=ty;i;i--)
re=xtr->qry(1,n,dfn[sty[i].fs],dfn[sty[i].sc],re,0);
return re;
}
int main()
{
n=read();m=read();k=read();
sk=1;
sk=((long long)sk<<k)-1;
for(int i=1;i<=n;i++)
a[i]=read();
for(int i=1;i<n;i++)
{
int x=read(),y=read();
ins(x,y);ins(y,x);
}
dfs1(1);
dfs2(1);
(xtr=new tree)->build(1,n);
while(m--)
{
char opt[10];
scanf("%s",opt);
uint x=read(),y=read();
if(opt[0]=='Q'){printf("%u\n",query(x,y)&sk);}
else{xtr->mdf(1,n,dfn[x],y);}
}
return 0;
}