前言
当暴力思路与题解中的“暴力”不同时,继续想优化往往就渐行渐远了…
所以当没有头绪时,要勇于跳出原有的转化!
这种位运算类型的优化似乎始终不在我的寄存器中…需要加强!
解析
不难想到按位考虑的
O
(
n
k
log
2
n
)
O(nk\log^2n)
O(nklog2n) 的树剖做法(LCT可以单log)。
考虑这样的实现:
f
0
/
1
f_{0/1}
f0/1 表示某一位原来是 0/1 目前的值。
合并:
f
o
p
=
f
r
,
f
l
,
o
p
f_{op}=f_{r,f_{l,op}}
fop=fr,fl,op
可以写成如下形式:
f
o
p
=
(
f
l
,
o
p
&
f
r
,
1
)
∣
(
(
f
l
,
o
p
⊕
1
)
&
f
r
,
0
)
f_{op}=(f_{l,op}\&f_{r,1})|((f_{l,op}\oplus1)\&f_{r,0})
fop=(fl,op&fr,1)∣((fl,op⊕1)&fr,0)。
那么我们就可以把 64 个布尔压成一个 unsigned long long
,从而进行快速合并。
这样就把复杂度的 k 拿掉了,时间复杂度
O
(
n
log
2
n
)
O(n\log^2n)
O(nlog2n)。
代码
1ull<<i
写成 1<<i
WA了半天…
#include<bits/stdc++.h>
#include<string>
using namespace std;
#define ll long long
#define ull unsigned ll
#define debug(...) fprintf(stderr,__VA_ARGS__)
#define ok debug("OK\n")
inline ll read() {
ll x(0),f(1);char c=getchar();
while(!isdigit(c)) {if(c=='-') f=-1;c=getchar();}
while(isdigit(c)) {x=(x<<1)+(x<<3)+c-'0';c=getchar();}
return x*f;
}
const int N=1e5+100;
const int mod=998244353;
bool mem1;
int n,m,k;
int op[N];
ull w[N],o;
int dep[N],siz[N],hson[N],top[N],fa[N],dfn[N],pos[N],tim;
vector<int>e[N];
void dfs1(int x,int f){
siz[x]=1;
dep[x]=dep[f]+1;
fa[x]=f;
for(int to:e[x]){
if(to==f) continue;
dfs1(to,x);
if(siz[to]>siz[hson[x]]) hson[x]=to;
siz[x]+=siz[to];
}
return;
}
void dfs2(int x,int tp){
top[x]=tp;
dfn[++tim]=x;pos[x]=tim;
if(hson[x]) dfs2(hson[x],tp);
for(int to:e[x]){
if(to==fa[x]||to==hson[x]) continue;
dfs2(to,to);
}
return;
}
#define mid ((l+r)>>1)
#define ls (k<<1)
#define rs (k<<1|1)
struct node{
ull w[2];
};
node operator + (const node &x,const node &y){
node o;
o.w[0]=(x.w[0]&y.w[1])|((~x.w[0])&y.w[0]);
o.w[1]=(x.w[1]&y.w[1])|((~x.w[1])&y.w[0]);
return o;
}
node tr1[N<<2],tr2[N<<2];
inline void pushup(int k){
tr1[k]=tr1[ls]+tr1[rs];
tr2[k]=tr2[rs]+tr2[ls];
}
void build(int k,int l,int r){
if(l==r){
int x=dfn[l];
if(op[x]==1){
tr1[k]=tr2[k]=(node){0,w[x]};
}
else if(op[x]==2){
tr1[k]=tr2[k]=(node){w[x],o};
}
else if(op[x]==3){
tr1[k]=tr2[k]=(node){w[x],o^w[x]};
}
//printf("k=%d (%d %d) %llu %llu\n",k,l,r,tr1[k].w[0],tr1[k].w[1]);
return;
}
build(ls,l,mid);
build(rs,mid+1,r);
pushup(k);
//printf("k=%d (%d %d) %llu %llu\n",k,l,r,tr1[k].w[0],tr1[k].w[1]);
}
void upd(int k,int l,int r,int p){
if(l==r){
int x=dfn[l];
if(op[x]==1){
tr1[k]=tr2[k]=(node){0,w[x]};
}
else if(op[x]==2){
tr1[k]=tr2[k]=(node){w[x],o};
}
else if(op[x]==3){
tr1[k]=tr2[k]=(node){w[x],o^w[x]};
}
return;
}
if(p<=mid) upd(ls,l,mid,p);
else upd(rs,mid+1,r,p);
pushup(k);
}
node ask(int k,int l,int r,int x,int y,int op){
//if(k==1) printf("ask: (%d %d) op=%d\n",x,y,op);
if(x<=l&&r<=y){
if(op==1) return tr1[k];
else return tr2[k];
}
if(y<=mid) return ask(ls,l,mid,x,y,op);
else if(x>mid) return ask(rs,mid+1,r,x,y,op);
else if(op==1) return ask(ls,l,mid,x,y,op)+ask(rs,mid+1,r,x,y,op);
else return ask(rs,mid+1,r,x,y,op)+ask(ls,l,mid,x,y,op);
}
#undef mid
#undef ls
#undef rs
node query(int x,int y){
node res1=(node){0,o},res2=(node){0,o};
while(top[x]!=top[y]){
if(dep[top[x]]>=dep[top[y]]){
res1=res1+ask(1,1,n,pos[top[x]],pos[x],2);
x=fa[top[x]];
}
else{
res2=ask(1,1,n,pos[top[y]],pos[y],1)+res2;
y=fa[top[y]];
}
}
if(dep[x]>=dep[y]) res1=res1+ask(1,1,n,pos[y],pos[x],2);
else res2=ask(1,1,n,pos[x],pos[y],1)+res2;
return res1+res2;
}
bool mem2;
signed main() {
#ifndef ONLINE_JUDGE
freopen("a.in","r",stdin);
freopen("a.out","w",stdout);
#endif
n=read();m=read();k=read();
if(k==0) o=0;
else{
o=1;
for(int i=0;i<k;i++) o=(o<<1)|1;
}
for(int i=1;i<=n;i++) scanf("%d%llu",&op[i],&w[i]);
for(int i=1;i<n;i++){
int x=read(),y=read();
e[x].push_back(y);
e[y].push_back(x);
}
dfs1(1,0);
dfs2(1,1);
build(1,1,n);
for(int i=1;i<=m;i++){
int oop,x,y;
ull z;
scanf("%d%d%d%llu",&oop,&x,&y,&z);
if(oop==2){
op[x]=y;w[x]=z;
upd(1,1,n,pos[x]);
}
else{
node o=query(x,y);
//printf("%llu %llu\n",o.w[0],o.w[1]);
ull res(0);
for(int i=k-1;i>=0;i--){
if(o.w[0]&(1<<i)) res+=(1<<i);
else if((o.w[1]&(1<<i))&&z>=(1<<i)){
z-=(1<<i);
res+=(1<<i);
}
}
printf("%llu\n",res);
}
}
return 0;
}
/*
3 1
2 3 3 1
1 1
*/