E-Eert Esiwtib
位运算考虑贡献时分0/1按位模拟考虑
fu,0/1/2f_{u,0/1/2}fu,0/1/2表示子树u中点(包括u)到u所有路径的或/与/异或值。
转移的时候我们要考虑两个东西,一个是位运算对于路径值的影响,另一个是位运算对于所有路径值的或/与/异或和的影响。
合并子树的时候自己稍微推下式子即可,按位并且0/1拆分考虑贡献更容易帮助理解。
Alkaid~题解
#include<bits/stdc++.h>
using namespace std;
using ll=long long;
template <class T=int> T rd()
{T res=0;T fg=1;char ch=getchar();while(!isdigit(ch)) {if(ch=='-') fg=-1;ch=getchar();}while( isdigit(ch)) res=(res<<1)+(res<<3)+(ch^48),ch=getchar();return res*fg;
}
const int N=200010;
int h[N],e[N],ne[N],op[N],idx;
void add(int a,int b,int c){e[idx]=b,ne[idx]=h[a],op[idx]=c,h[a]=idx++;}
int n,m;
ll val[N];
vector<pair<int,int>> q[105];
ll f[N][3],g[N][3];
ll ans[N][3];
int sz[N];
void update(int u,int v,int op)
{if(op==0){f[u][0]|=f[v][0]|val[u];f[u][1]&=f[v][1]|val[u];f[u][2]^=(sz[v]&1?val[u]:0)|(~val[u]&f[v][2]);}else if(op==1){f[u][0]|=f[v][0]&val[u];f[u][1]&=f[v][1]&val[u];f[u][2]^=f[v][2]&val[u];}else{f[u][0]|=(f[v][0]&~val[u])|(~f[v][1]&val[u]);f[u][1]&=(f[v][1]&~val[u])|(~f[v][0]&val[u]);f[u][2]^=(sz[v]&1?val[u]:0)^f[v][2];}
}
void dfs(int u,int fa)
{sz[u]=1;f[u][0]=0; // 或f[u][1]=-1;// 与f[u][2]=0; // 异或for(int i=h[u];i!=-1;i=ne[i]){int v=e[i];if(v==fa) continue;dfs(v,u);sz[u]+=sz[v];update(u,v,op[i]);}memcpy(g[u],f[u],sizeof f[u]);f[u][0]|=val[u];f[u][1]&=val[u];f[u][2]^=val[u];
}
int main()
{n=rd(),m=rd();memset(h,-1,sizeof h);for(int i=1;i<=n;i++) val[i]=rd<ll>();for(int i=2;i<=n;i++) {int u=rd(),op=rd();add(u,i,op);}for(int i=1;i<=m;i++){int d=rd(),u=rd();q[d].push_back({u,i});}for(int d=0;d<=100;d++){if(d) for(int i=1;i<=n;i++) val[i]+=i;dfs(1,0);for(auto&[u,k]:q[d]) memcpy(ans[k],g[u],sizeof g[u]);}for(int i=1;i<=m;i++) printf("%lld %lld %lld\n",ans[i][0],ans[i][1],ans[i][2]);return 0;
}