[BZOJ2908]又是nand
Description
首先知道A nand B=not(A and B) (运算操作限制了数位位数为K)比如2 nand 3,K=3,则2 nand 3=not (2 and 3)=not 2=5。给出一棵树,树上每个点都有点权,定义树上从a到b的费用为0与路径上的点的权值顺次nand的结果,例如:从2号点到5号点顺次经过2->3->5,权值分别为5、7、2,K=3,那么最终结果为0 nand 5 nand 7 nand 2=7 nand 7 nand 2=0 nand 2=7,现在这棵树需要支持以下操作。
① Replace a b:将点a(1≤a≤N)的权值改为b。
② Query a b:输出点a到点b的费用。
请众神给出一个程序支持这些操作。
Input
第一行N,M,K,树的节点数量、总操作个数和运算位数。
接下来一行N个数字,依次表示节点i的权值。
接下来N-1行,每行两个数字a,b(1≤a,b≤N)表示a,b间有一条树边。
接下来M行,每行一个操作,为以上2类操作之一。
N、M≤100000,K≤32
Output
对于操作②每个输出一行,如题目所述。
Sample Input
3 3 3
2 7 3
1 2
2 3
Query 2 3
Replace 1 3
Query 1 1
Sample Output
4
7
这题思维难度挺大。。。因为nand不满足结合律,所以甚是难受。。。
但是网上介绍了一个叫做拆位的方法
首先树链剖分,然后对于每一位,都用线段树维护tl[t][p],代表如果该位是t,从左边过来这个区间后会变成什么数;tr[t][p]代表如果该位是t,从右边过来这个区间后会变成什么数,然后就可以从a到lca再到b询问就好了
/*program from Wolfycz*/
#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define inf 0x7f7f7f7f
using namespace std;
typedef long long ll;
typedef unsigned int ui;
typedef unsigned long long ull;
inline int read(){
int 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<<1)+(x<<3)+ch-'0';
return x*f;
}
inline void print(int x){
if (x>=10) print(x/10);
putchar(x%10+'0');
}
const int N=1e5,K=33;
int ID[N+10],dfn[N+10],n,m,k;
ui v[N+10];
struct Segment{
#define ls (p<<1)
#define rs (p<<1|1)
bool tr[2][(N<<2)+10],tl[2][(N<<2)+10];
void updata(int p){
tl[0][p]=tl[tl[0][ls]][rs],tr[0][p]=tr[tr[0][rs]][ls];
tl[1][p]=tl[tl[1][ls]][rs],tr[1][p]=tr[tr[1][rs]][ls];
}
void build(int p,int l,int r,int x){
if (l==r){
tl[0][p]=1,tl[1][p]=!((v[dfn[l]]>>x)&1);
tr[0][p]=1,tr[1][p]=!((v[dfn[l]]>>x)&1);
return;
}
int mid=(l+r)>>1;
build(ls,l,mid,x),build(rs,mid+1,r,x);
updata(p);
}
void change(int p,int l,int r,int x,bool v){
if (l==r){
tl[0][p]=1,tl[1][p]=!v;
tr[0][p]=1,tr[1][p]=!v;
return;
}
int mid=(l+r)>>1;
if (x<=mid) change(ls,l,mid,x,v);
else change(rs,mid+1,r,x,v);
updata(p);
}
bool ql(int p,int l,int r,int x,int y,bool z){
if (x<=l&&r<=y) return tl[z][p];
int mid=(l+r)>>1;
if (y<=mid) return ql(ls,l,mid,x,y,z);
if (x>mid) return ql(rs,mid+1,r,x,y,z);
return ql(rs,mid+1,r,x,y,ql(ls,l,mid,x,y,z));
}
bool qr(int p,int l,int r,int x,int y,int z){
if (x<=l&&r<=y) return tr[z][p];
int mid=(l+r)>>1;
if (y<=mid) return qr(ls,l,mid,x,y,z);
if (x>mid) return qr(rs,mid+1,r,x,y,z);
return qr(ls,l,mid,x,y,qr(rs,mid+1,r,x,y,z));
}
}Tree[K];
struct S1{
int pre[(N<<1)+10],now[N+10],child[(N<<1)+10],tot,cnt;
int fa[N+10],size[N+10],deep[N+10],top[N+10],Rem[N+10],stack[N+10];
void join(int x,int y){pre[++tot]=now[x],now[x]=tot,child[tot]=y;}
void insert(int x,int y){join(x,y),join(y,x);}
void dfs1(int x,int Deep){
deep[x]=Deep,size[x]=1;
for (int p=now[x],son=child[p];p;p=pre[p],son=child[p]){
if (son==fa[x]) continue;
fa[son]=x;
dfs1(son,Deep+1);
size[x]+=size[son];
if (size[Rem[x]]<size[son]) Rem[x]=son;
}
}
void dfs2(int x){
if (!x) return;
dfn[ID[x]=++cnt]=x;
top[x]=Rem[fa[x]]==x?top[fa[x]]:x;
dfs2(Rem[x]);
for (int p=now[x],son=child[p];p;p=pre[p],son=child[p]){
if (son==fa[x]||son==Rem[x]) continue;
dfs2(son);
}
}
void work(int x,int y){
ui res=0; int Top=0;
while (top[x]!=top[y]){
if (deep[top[x]]>=deep[top[y]]){
for (int i=0;i<k;i++) res=res-(res&(1<<i))+(Tree[i].qr(1,1,n,ID[top[x]],ID[x],(res>>i)&1)<<i);
x=fa[top[x]];
}else stack[++Top]=y,y=fa[top[y]];
}
for (int i=0;i<k;i++){
if (deep[x]<deep[y]) res=res-(res&(1<<i))+(Tree[i].ql(1,1,n,ID[x],ID[y],(res>>i)&1)<<i);
else res=res-(res&(1<<i))+(Tree[i].qr(1,1,n,ID[y],ID[x],(res>>i)&1)<<i);
}
for (int i=Top;i;i--) for (int j=0;j<k;j++) res=res-(res&(1<<j))+(Tree[j].ql(1,1,n,ID[top[stack[i]]],ID[stack[i]],(res>>j)&1)<<j);
printf("%u\n",res);
}
}T;
int main(){
n=read(),m=read(),k=read();
for (int i=1;i<=n;i++) scanf("%u",&v[i]);
for (int i=1;i<n;i++){
int x=read(),y=read();
T.insert(x,y);
}
T.dfs1(1,1),T.dfs2(1);
for (int i=0;i<k;i++) Tree[i].build(1,1,n,i);
char s[10];
for (int i=1;i<=m;i++){
scanf("%s",s);
if (s[0]=='R'){
int x=read();scanf("%u",&v[x]);
for (int j=0;j<k;j++) Tree[j].change(1,1,n,ID[x],(v[x]>>j)&1);
}
if (s[0]=='Q'){
int x=read(),y=read();
T.work(x,y);
}
}
return 0;
}