前言
当暴力思路与题解中的“暴力”不同时,继续想优化往往就渐行渐远了…
所以当没有头绪时,要勇于跳出原有的转化!
这种位运算类型的优化似乎始终不在我的寄存器中…需要加强!
解析
不难想到按位考虑的 O(nklog2n)O(nk\log^2n)O(nklog2n) 的树剖做法(LCT可以单log)。
考虑这样的实现:f0/1f_{0/1}f0/1 表示某一位原来是 0/1 目前的值。
合并:fop=fr,fl,opf_{op}=f_{r,f_{l,op}}fop=fr,fl,op
可以写成如下形式:fop=(fl,op&fr,1)∣((fl,op⊕1)&fr,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(nlog2n)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 rsnode 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_JUDGEfreopen("a.in","r",stdin);freopen("a.out","w",stdout);
#endifn=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 12 3 3 11 1
*/