传送门
解:首先异或也是具有前缀性质的,b[i]代表从i点异或到根节点的值,那么i到j的异或和就是b[i]^b[j],但是题目求得是i~j路径上所以子路径的异或和,显然是不能一个一个的求,思路也很巧妙,我们将这条路径上所有的b[]拿出来,对每一位进行维护,看看这些数在这一位上有多少1,和0,那么这一位对结果的贡献不就是(1<<i)*num1*num0吗;还有修改,首先修改影响的肯定是该节点下面子树所有的节点,修改还是每一位每一位的看,如果有一位的1变成了0,那说明0的个数和1的个数互换,rev一下就可以。这里用线段树去维护每一位就可以了。剩下的部分就是数链剖分的基本操作了。
#include<bits/stdc++.h>
#define il inline
#define pb push_back
#define ms(_data,v) memset(_data,v,sizeof(_data))
#define SZ(a) int((a).size())
using namespace std;
typedef long long ll;
const ll inf=0x3f3f3f3f;
const int N=5e4+5;
//il int Add(ll &x,ll y) {return x=x+y>=mod?x+y-mod:x+y;}
//il int Mul(ll &x,ll y) {return x=x*y>=mod?x*y%mod:x*y;}
int n,q,ed[N];
struct node{int to,w;};
vector<node> eg[N];
int dep[N],fa[N],sz[N],son[N],id[N],bel[N],cnt=0;
int b[N],nb[N]; //b[i]:i到根异或的结果
bool vis[N];
void dfs1(int x,int ff){
vis[x]=true;
dep[x]=dep[ff]+1;
fa[x]=ff,sz[x]=1;
int mx=-1,to;
for(int i=0;i<SZ(eg[x]);++i){
to=eg[x][i].to;
if(to==ff || vis[to]) continue;
b[to]=b[x]^eg[x][i].w;
ed[to]=eg[x][i].w;
dfs1(to,x);
sz[x]+=sz[to];
if(sz[to]>mx) son[x]=to,mx=sz[to];
}
}
void dfs2(int x,int topx){
id[x]=++cnt;
bel[x]=topx,nb[cnt]=b[x];
if(!son[x]) return ;
dfs2(son[x],topx);
for(int i=0,to;i<SZ(eg[x]);++i){
to=eg[x][i].to;
if(to==fa[x] || to==son[x]) continue;
dfs2(to,to);
}
}
struct T{
int n1,n0;
bool rev;
T(){n1=0,n0=0,rev=0;}
}t[15][N<<3];
il T add(T a,T b){
T res;
res.n1=a.n1+b.n1;
res.n0=a.n0+b.n0;
return res;
}
void pushdown(int k,int rt){
if(t[k][rt].rev){
swap(t[k][rt<<1].n1,t[k][rt<<1].n0);
swap(t[k][rt<<1|1].n1,t[k][rt<<1|1].n0);
t[k][rt<<1].rev^=1;
t[k][rt<<1|1].rev^=1;
t[k][rt].rev=0;
}
}
void build(int l,int r,int rt,int k){
// cout<<"build "<<l<<" "<<r<<" "<<rt<<" "<<k<<endl;
if(l==r){
if((nb[l]>>k)&1) t[k][rt].n1=1,t[k][rt].n0=0;
else t[k][rt].n1=0,t[k][rt].n0=1;
return ;
}
int mid=(l+r)>>1;
build(l,mid,rt<<1,k),build(mid+1,r,rt<<1|1,k);
t[k][rt]=add(t[k][rt<<1],t[k][rt<<1|1]);
}
void rev(int l,int r,int L,int R,int rt,int k){
if(L<=l && R>=r){
swap(t[k][rt].n1,t[k][rt].n0);
t[k][rt].rev^=1;
return ;
}
pushdown(k,rt);
int mid=(l+r)>>1;
if(L<=mid) rev(l,mid,L,R,rt<<1,k);
if(R>mid) rev(mid+1,r,L,R,rt<<1|1,k);
t[k][rt]=add(t[k][rt<<1],t[k][rt<<1|1]);
}
void update(int u,int w){
for(int i=0;i<=10;++i){
if(((w^ed[u])>>i)&1) rev(1,n,id[u],id[u]+sz[u]-1,1,i);
}
ed[u]=w;
}
T query(int l,int r,int L,int R,int rt,int k){
if(L<=l && R>=r){
return t[k][rt];
}
int mid=(l+r)>>1;
pushdown(k,rt);
T res,ls,rs;
if(L<=mid){
ls=query(l,mid,L,R,rt<<1,k);
res.n0+=ls.n0,res.n1+=ls.n1;
}
if(R>mid){
rs=query(mid+1,r,L,R,rt<<1|1,k);
res.n0+=rs.n0,res.n1+=rs.n1;
}
return res;
}
ll query(int u,int v){
ll res=0;
int pu=u,pv=v;
for(int i=0;i<=10;++i){
u=pu,v=pv;
T rs,tp;
while(bel[u]!=bel[v]){
if(dep[bel[u]]<dep[bel[v]]) swap(u,v);
tp=query(1,n,id[bel[u]],id[u],1,i);
rs=add(rs,tp);
u=fa[bel[u]];
}
if(dep[u]>dep[v]) swap(u,v);
rs=add(rs,query(1,n,id[u],id[v],1,i));
res+=(1LL<<i)*rs.n0*rs.n1;
}
return res;
}
int main(){
std::ios::sync_with_stdio(0);cin.tie(0);
cin>>n>>q;
int u,v,w,op;
for(int i=1;i<=n-1;++i){
cin>>u>>v>>w;
eg[u].pb(node{v,w});
eg[v].pb(node{u,w});
}
dfs1(1,0);
dfs2(1,1);
for(int i=0;i<=10;++i) build(1,n,1,i);
while(q--){
cin>>op>>u>>v;
if(op==1) cout<<query(u,v)<<endl;
else{
cin>>w;
if(u!=fa[v]) swap(u,v);
update(v,w);
}
}
return 0;
}