解题思路:这道题据说是树链剖分,所以也学习了一下。
http://blog.sina.com.cn/s/blog_7a1746820100wp67.html
不同的是这里是点权值,我按照相似的处理方式,不知道为什么WA了。。。调了好久。。
#include<iostream> #include<cstdio> #include<cstring> using namespace std; const int maxn = 100005; struct Segment { int l,r,sum; }tree[maxn<<2]; struct Edge { int to,next; }edge[maxn<<1]; int A[maxn],son[maxn],top[maxn],w[maxn]; int dep[maxn],fa[maxn],size[maxn]; int cnt,num,pre[maxn]; int n,q,idx[maxn]; void addedge(int u,int v) { edge[cnt].to = v; edge[cnt].next = pre[u]; pre[u] = cnt++; } void dfs(int u) { size[u] = 1; son[u] = 0; int tmp = 0; for(int i = pre[u]; i != -1; i = edge[i].next) { int v = edge[i].to; if(fa[u] == v) continue; fa[v] = u; dep[v] = dep[u] + 1; dfs(v); size[u] += size[v]; if(size[v] > tmp) { tmp = size[v]; son[u] = v; } } } void build_tree(int u,int tp) { w[u] = ++num; top[u] = tp; idx[num] = u; if(son[u] != 0) build_tree(son[u],tp); for(int i = pre[u]; i != -1; i = edge[i].next) { int v = edge[i].to; if(v == son[u] || fa[u] == v) continue; build_tree(v,v); } } void build_Segment(int rt,int l,int r) { tree[rt].l = l, tree[rt].r = r; tree[rt].sum = 0; if(l == r) return; int mid = (l + r) >> 1; build_Segment(rt<<1,l,mid); build_Segment(rt<<1|1,mid+1,r); } void update(int rt,int pos,int val) { if(tree[rt].l == tree[rt].r) { tree[rt].sum = val; return; } int mid = (tree[rt].l + tree[rt].r) >> 1; if(pos <= mid) update(rt<<1,pos,val); else update(rt<<1|1,pos,val); tree[rt].sum = tree[rt<<1].sum ^ tree[rt<<1|1].sum; } int query(int rt,int l,int r) { if(l <= tree[rt].l && tree[rt].r <= r) return tree[rt].sum; int mid = (tree[rt].l + tree[rt].r) >> 1; int ans = 0; if(l <= mid) ans ^= query(rt<<1,l,r); if(mid < r) ans ^= query(rt<<1|1,l,r); return ans; } int find(int l,int r) { int f1 = top[l], f2 = top[r]; int ans = 0; while(f1 != f2) { if(dep[f1] < dep[f2]) { swap(f1,f2); swap(l,r); } ans ^= query(1,w[f1],w[l]); l = fa[f1], f1 = top[l]; } if(l == r) return ans^A[f1]; if(dep[l] > dep[r]) swap(l,r); return ans ^= query(1,w[son[l]],w[r])^A[f1]; } int main() { int t,u,v,op; scanf("%d",&t); while(t--) { scanf("%d%d",&n,&q); memset(pre,-1,sizeof(pre)); cnt = num = 0; for(int i = 1; i < n; i++) { scanf("%d%d",&u,&v); addedge(u,v); addedge(v,u); } dep[1] = 0; dfs(1); build_tree(1,1); build_Segment(1,1,num); for(int i = 1; i <= n; i++) { scanf("%d",&A[i]); A[i]++; update(1,w[i],A[i]); } for(int i = 1; i <= q; i++) { scanf("%d%d%d",&op,&u,&v); if(op == 0) { A[u] = v + 1; update(1,w[u],A[u]); } else { int ans = find(u,v); printf("%d\n",ans-1); } } } return 0; }
PS:今天早上把这道题给A了,参考了一下别人的代码,发现自己的代码不一样的地方就是在find函数里,我是按照边更新的方式去写的,而这道题是点更新。关键是最后f1=f2后,如何把根节点加入进去。但仔细想想还是没明白我的为什么错了。
#include<iostream> #include<cstdio> #include<cstring> using namespace std; const int maxn = 100005; struct Segment { int l,r,sum; }tree[maxn<<2]; struct Edge { int to,next; }edge[maxn<<1]; int A[maxn],son[maxn],top[maxn],w[maxn]; int dep[maxn],fa[maxn],size[maxn]; int cnt,num,pre[maxn]; int n,q; void addedge(int u,int v) { edge[cnt].to = v; edge[cnt].next = pre[u]; pre[u] = cnt++; } void dfs(int u) { size[u] = 1; son[u] = 0; int tmp = 0; for(int i = pre[u]; i != -1; i = edge[i].next) { int v = edge[i].to; if(fa[u] == v) continue; fa[v] = u; dep[v] = dep[u] + 1; dfs(v); size[u] += size[v]; if(size[v] > tmp) { tmp = size[v]; son[u] = v; } } } void build_tree(int u,int tp) { w[u] = ++num; top[u] = tp; if(son[u] != 0) build_tree(son[u],tp); for(int i = pre[u]; i != -1; i = edge[i].next) { int v = edge[i].to; if(v == son[u] || fa[u] == v) continue; build_tree(v,v); } } void build_Segment(int rt,int l,int r) { tree[rt].l = l, tree[rt].r = r; tree[rt].sum = 0; if(l == r) return; int mid = (l + r) >> 1; build_Segment(rt<<1,l,mid); build_Segment(rt<<1|1,mid+1,r); } void update(int rt,int pos,int val) { if(tree[rt].l == tree[rt].r) { tree[rt].sum = val; return; } int mid = (tree[rt].l + tree[rt].r) >> 1; if(pos <= mid) update(rt<<1,pos,val); else update(rt<<1|1,pos,val); tree[rt].sum = tree[rt<<1].sum ^ tree[rt<<1|1].sum; } int query(int rt,int l,int r) { if(l <= tree[rt].l && tree[rt].r <= r) return tree[rt].sum; int mid = (tree[rt].l + tree[rt].r) >> 1; int ans = 0; if(l <= mid) ans ^= query(rt<<1,l,r); if(mid < r) ans ^= query(rt<<1|1,l,r); return ans; } int find(int l,int r) { int f1 = top[l], f2 = top[r]; int ans = 0; while(f1 != f2) { if(dep[f1] < dep[f2]) { swap(f1,f2); swap(l,r); } ans ^= query(1,w[f1],w[l]); l = fa[f1], f1 = top[l]; } if(dep[l] > dep[r]) swap(l,r);<span style="white-space:pre"> </span>//没有比较l与r,这是关键点 return ans ^= query(1,w[l],w[r]); } int main() { int t,u,v,op; scanf("%d",&t); while(t--) { scanf("%d%d",&n,&q); memset(pre,-1,sizeof(pre)); cnt = num = 0; for(int i = 1; i < n; i++) { scanf("%d%d",&u,&v); addedge(u,v); addedge(v,u); } dep[1] = 0; dfs(1); build_tree(1,1); build_Segment(1,1,num); for(int i = 1; i <= n; i++) { scanf("%d",&A[i]); update(1,w[i],A[i]+1); } for(int i = 1; i <= q; i++) { scanf("%d%d%d",&op,&u,&v); if(op == 0) update(1,w[u],v+1); else { int ans = find(u,v); printf("%d\n",ans-1); } } } return 0; }