用的是树剖和线段树,存储异或前缀和,每次操作修改子树,但是 WA 到 pts.
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <cctype>
#define ll long long
#define inf 1023456789
using namespace std;
inline int read(){
int x=0,w=0;char ch=getchar();
while (!isdigit(ch))w|=ch=='-',ch=getchar();
while (isdigit(ch))x=(x<<1)+(x<<3)+ch-'0',ch=getchar();
return w?-x:x;
}
struct node{
int to, nxt, val;
}e[1000005];
int n, q, head[100005], cnt;
inline void add(int from, int to, int val){
e[++cnt].nxt = head[from];
head[from] = cnt;
e[cnt].to = to;
e[cnt].val = val;
}
int f[100005], dep[100005], son[100005], siz[100005], vv[100005], two[15];
inline void dfs1(int p, int fa, int w){
vv[p] = w;
f[p] = fa;
dep[p] = dep[fa] + 1;
siz[p] = 1;
for(int i = head[p]; i; i = e[i].nxt ){
if(e[i].to == fa) continue;
dfs1(e[i].to , p, e[i].val ^ w);
siz[p] += siz[e[i].to ];
if(siz[son[p]] < siz[e[i].to ]) son[p] = e[i].to ;
}
}
int id[100005], top[100005], tot, vvv[100005];
inline void dfs2(int p, int topf){
top[p] = topf;
id[p] = ++tot;
vvv[tot] = vv[p];
if(!son[p]) return ;
dfs2(son[p] , topf);
for(int i = head[p]; i; i = e[i].nxt ){
if(e[i].to == f[p] || e[i].to == son[p]) continue ;
dfs2(e[i].to ,e[i].to );
}
}
struct Segment_Tree{
int val[12];
int tag;
}a[5000005];
inline int ls(int p){
return p << 1;
}
inline int rs(int p){
return p << 1 | 1;
}
inline void update(int p){
for(int i = 0; i <= 10; i++)
a[p].val[i] = a[ls(p)].val[i] + a[rs(p)].val[i];
}
inline void push_up(int p, int l, int r, int k){
a[p].tag ^= k;
int now = 0;
while(k){
if(k & 1) a[p].val[now] = r - l + 1 - a[p].val[now];
now ++;
k >>= 1;
}
}
inline void push_down(int p, int l, int r){
if(!a[p].tag ) return ;
int mid = l + r >> 1;
push_up(ls(p), l, mid, a[p].tag );
push_up(rs(p), mid + 1, r, a[p].tag );
a[p].tag = 0;
}
inline void build(int p, int l, int r){
if(l == r){
int now = 0, w = vvv[l];
while(w){
a[p].val[now] = w & 1;
w >>= 1;
now++;
}
return ;
}
int mid = l + r >> 1;
build(ls(p), l, mid);
build(rs(p), mid + 1, r);
update(p);
}
int ans[12];
inline void modify(int p, int l, int r, int L, int R, int k){
if(L <= l && r <= R){
int now = 0, w = k;
while(w){
if(w & 1)
a[p].val[now] = r - l + 1 - a[p].val[now] ;
w >>= 1;
now++;
}
a[p].tag ^= k;
return ;
}
push_down(p, l, r);
int mid = l + r >> 1;
if(L <= mid) modify(ls(p), l, mid, L, R, k);
if(mid < R) modify(rs(p), mid + 1, r, L, R, k);
update(p);
}
inline void query(int p, int l, int r, int L, int R){
if(L <= l && r <= R){
for(int i = 0; i <= 10; i++)
ans[i] += a[p].val[i];
return ;
}
push_down(p, l, r);
int mid = l + r >> 1;
if(L <= mid) query(ls(p), l, mid, L, R);
if(mid < R) query(rs(p), mid + 1, r, L, R);
update(p);
}
inline ll query_range(int u, int v){
int sum = dep[u] + dep[v];
for(int i = 0; i <= 10; i++) ans[i] = 0;
while(top[u] != top[v]){
if(dep[top[u]] < dep[top[v]]) swap(u, v);
query(1, 1, n, id[top[u]], id[u]);
u = f[top[u]];
}
if(dep[u] < dep[v]) swap(u, v);
query(1, 1, n, id[v], id[u]);
sum += - 2 * dep[v] + 1;
ll res = 0;
for(int i = 0; i <= 10; i++){
res += (ll) two[i] * ans[i] * (sum - ans[i]);
}
return res;
}
inline void up_son(int p, int k){
modify(1, 1, n, id[p], id[p] + siz[p] - 1, k);
}
int main(){
n = read(), q = read();
two[0] = 1;
for(int i = 1; i <= 10; i++) two[i] = two[i - 1] * 2;
for(int i = 1; i < n; i++){
int x = read(), y = read(), z = read();
add(x, y, z);
add(y, x, z);
}
dfs1(1, 0, 0);
dfs2(1, 1);
build(1, 1, n);
for(int i = 1; i <= q; i++){
int opt = read();
if(opt == 1){
int u = read(), v = read();
printf("%lld\n",query_range(u, v));
}
else {
int u = read(), v = read(), w = read();
int ww = w;
if(f[u] == v){
w ^= vvv[u];
vvv[u] = ww;
up_son(u, w);
}
else {
w ^= vvv[v];
vvv[v] = ww;
up_son(v, w);
}
}
}
}