牛客练习赛58 F-XOR TREE(结论+树链剖分+线段树)
链接:https://ac.nowcoder.com/acm/contest/4090/F
来源:牛客网
XOR TREE
时间限制:C/C++ 1秒,其他语言2秒
空间限制:C/C++ 262144K,其他语言524288K
64bit IO Format: %lld
题目描述
给出一颗n{n}n个结点n−1{n-1}n−1条边的带权树,第i{i}i个结点的权值为aia_{i}ai 。
定义点u{u}u到点v{v}v的路径的长度为点u{u}u到点v{v}v的最短路径上的所有结点的权值的异或和。
单独一个点不算做路径。
现在要求你维护q{q}q个操作:
1{1}1 u{u}u x{x}x将点u{u}u的权值修改为x{x}x
2{2}2 u{u}u v{v}v求点u{u}u到点v{v}v之间的所有子路径的长度的异或和
输入描述:
第一行两个整数n,q{n,q}n,q 第二行n个整数表示a1,a2...an{a_{1},a_{2}...a_{n}}a1,a2...an 接下来n-1行每行两个整数ui,vi{u_{i},v_{i}}ui,vi表示ui,vi{u_{i},v_{i}}ui,vi之间有一条边 接下来q行每行三个整数表示一个查询,数据保证对于查询2{2}2,满足u!=v{u!=v}u!=v。
输出描述:
对于每个查询2{2}2输出一行一个整数表示答案
示例1
输入
5 3 1 2 3 4 5 1 2 2 3 3 4 4 5 2 1 5 1 2 8 2 1 5
输出
6 12
说明
让f(u,v){f(u,v)}f(u,v)表示点u{u}u到点v{v}v最短路径上所有结点的权值的异或和,那么第一个查询的答案为: f(1,2)⨁f(1,3)⨁f(1,4)⨁f(1,5)⨁f(2,3)⨁f(2,4)⨁f(2,5)⨁f(3,4)⨁f(3,5)⨁f(4,5)=6{f(1,2)\bigoplus f(1,3)\bigoplus f(1,4)\bigoplus f(1,5)\bigoplus f(2,3)\bigoplus f(2,4)\bigoplus f(2,5)\bigoplus f(3,4)\bigoplus f(3,5)\bigoplus f(4,5)=6}f(1,2)⨁f(1,3)⨁f(1,4)⨁f(1,5)⨁f(2,3)⨁f(2,4)⨁f(2,5)⨁f(3,4)⨁f(3,5)⨁f(4,5)=6 其中f(1,4)=1⨁2⨁3⨁4,f(2,5)=2⨁3⨁4⨁5{f(1,4)=1\bigoplus 2\bigoplus 3\bigoplus 4,f(2,5)=2\bigoplus 3\bigoplus 4\bigoplus 5}f(1,4)=1⨁2⨁3⨁4,f(2,5)=2⨁3⨁4⨁5,其它的类似。
备注:
1<=u,v<=n,q<=2e5 1<=ai,x<=1e9
思路:
考虑到异或的性质,即一个数异或两次就会相消
经过分析路径中每一个点对答案的贡献发现:
- 如果路径的长度是奇数个点,那么等效于所有偶数次序的点被记录一次
- 如果路径长度是偶数个点,那么所有点都被计入一次
每一个节点的奇偶次序可以用有根树的节点深度的奇偶来表示。
那么我们不妨建立2个基于节点的dfs序的线段树,
分别为只维护深度为偶数的节点权值,(即奇数节点权值为0),不妨称为A树,
和维护深度为奇数的节点权值,(即偶数节点权值为0),不妨称为B树.
对于每一个询问:
如果路径链中有偶数个节点,则答案为A树上的路径答案异或上B树上的路径答案。
如果路径链中有奇数个节点,则答案为A树上的路径答案或B树上的路径答案,具体是哪个树上的要根据端点的奇偶性判断。
代码:
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #include <cmath> #include <queue> #include <stack> #include <map> #include <set> #include <vector> #include <iomanip> #include <sstream> #include <bitset> #define ALL(x) (x).begin(), (x).end() #define sz(a) int(a.size()) #define rep(i,x,n) for(int i=x;i<n;i++) #define repd(i,x,n) for(int i=x;i<=n;i++) #define pii pair<int,int> #define pll pair<long long ,long long> #define gbtb ios::sync_with_stdio(false),cin.tie(0),cout.tie(0) #define MS0(X) memset((X), 0, sizeof((X))) #define MSC0(X) memset((X), '\0', sizeof((X))) #define pb push_back #define mp make_pair #define fi first #define se second #define eps 1e-6 #define chu(x) cout<<"["<<#x<<" "<<(x)<<"]"<<endl #define du3(a,b,c) scanf("%d %d %d",&(a),&(b),&(c)) #define du2(a,b) scanf("%d %d",&(a),&(b)) #define du1(a) scanf("%d",&(a)); using namespace std; typedef long long ll; ll gcd(ll a, ll b) {return b ? gcd(b, a % b) : a;} ll lcm(ll a, ll b) {return a / gcd(a, b) * b;} ll powmod(ll a, ll b, ll MOD) { if (a == 0ll) {return 0ll;} a %= MOD; ll ans = 1; while (b) {if (b & 1) {ans = ans * a % MOD;} a = a * a % MOD; b >>= 1;} return ans;} ll poww(ll a, ll b) { if (a == 0ll) {return 0ll;} ll ans = 1; while (b) {if (b & 1) {ans = ans * a ;} a = a * a ; b >>= 1;} return ans;} void Pv(const vector<int> &V) {int Len = sz(V); for (int i = 0; i < Len; ++i) {printf("%d", V[i] ); if (i != Len - 1) {printf(" ");} else {printf("\n");}}} void Pvl(const vector<ll> &V) {int Len = sz(V); for (int i = 0; i < Len; ++i) {printf("%lld", V[i] ); if (i != Len - 1) {printf(" ");} else {printf("\n");}}} inline long long readll() {long long tmp = 0, fh = 1; char c = getchar(); while (c < '0' || c > '9') {if (c == '-') fh = -1; c = getchar();} while (c >= '0' && c <= '9') tmp = tmp * 10 + c - 48, c = getchar(); return tmp * fh;} inline int readint() {int tmp = 0, fh = 1; char c = getchar(); while (c < '0' || c > '9') {if (c == '-') fh = -1; c = getchar();} while (c >= '0' && c <= '9') tmp = tmp * 10 + c - 48, c = getchar(); return tmp * fh;} const int maxn = 200010; const int inf = 0x3f3f3f3f; /*** TEMPLATE CODE * * STARTS HERE ***/ int n, m; int root; int a[maxn];// 鲁玫脢录碌茫脠篓 int wt[maxn];// 脨脗陆篓卤脿潞脜碌茫脠篓隆拢 int cnt;// 卤脿潞脜脫脙碌脛卤盲脕驴 int top[maxn];// 脣霉脭脷脰脴脕麓碌脛露楼碌茫卤脿潞脜 int id[maxn];//陆脷碌茫碌脛脨脗卤脿潞脜隆拢 std::vector<int> son[maxn]; int SZ[maxn];// 脳脫脢媒麓贸脨隆 int wson[maxn];// 脰脴露霉脳脫 int fa[maxn];// 赂赂陆脷碌茫 int dep[maxn];// 陆脷碌茫碌脛脡卯露脠 void dfs1(int id, int pre, int step) // 脦卢禄陇鲁枚sz,wson,fa,dep { dep[id] = step; fa[id] = pre; SZ[id] = 1; int maxson = -1; for (auto x : son[id]) { if (x != pre) { dfs1(x, id, step + 1); SZ[id] += SZ[x]; if (SZ[x] > maxson) { maxson = SZ[x]; wson[id] = x; } } } } //麓娄脌铆鲁枚top[],wt[],id[] void dfs2(int u, int topf) { id[u] = ++cnt; wt[cnt] = a[u]; top[u] = topf; if (!wson[u]) // 脙禄露霉脳脫脢卤脰卤陆脫陆谩脢酶 { return ; } dfs2(wson[u], topf); // 脧脠麓娄脌铆脰脴露霉脳脫 for (auto x : son[u]) { if (x == wson[u] || x == fa[u]) //脰禄麓娄脌铆脟谩露霉脳脫 { continue; } dfs2(x, x); // 脙驴赂枚脟谩露霉脳脫脪脭脳脭录潞脦陋top } } int lca(int x, int y) { for (; top[x] != top[y]; dep[top[x]] > dep[top[y]] ? x = fa[top[x]] : y = fa[top[y]]); return dep[x] < dep[y] ? x : y; } int dist(int x, int y) { int l = lca(x, y); return dep[x] + dep[y] - 2 * dep[l]; } struct node { int l, r; int val; } A[maxn << 2], B[maxn << 2]; void build(node *segment_tree, int rt, int l, int r) { segment_tree[rt].l = l; segment_tree[rt].r = r; if (l == r) { return ; } int mid = (l + r) >> 1; build(segment_tree, rt << 1, l, mid); build(segment_tree, rt << 1 | 1, mid + 1, r); } void pushup(node *segment_tree, int rt) { segment_tree[rt].val = segment_tree[rt << 1].val ^ segment_tree[rt << 1 | 1].val; } void modify(node *segment_tree, int rt, int key, int x) { if (segment_tree[rt].l == key && segment_tree[rt].r == key) { segment_tree[rt].val = x; return ; } int mid = (segment_tree[rt].l + segment_tree[rt].r) >> 1; if (key <= mid) { modify(segment_tree, rt << 1, key, x); } else { modify(segment_tree, rt << 1 | 1, key, x); } pushup(segment_tree, rt); } int query(node *segment_tree, int rt, int l, int r) { if (l <= segment_tree[rt].l && segment_tree[rt].r <= r) { return segment_tree[rt].val; } int mid = segment_tree[rt].l + segment_tree[rt].r >> 1; int res = 0; if (r > mid) { res ^= query(segment_tree, rt << 1 | 1, l, r); } if (l <= mid) { res ^= query(segment_tree, rt << 1, l, r); } return res; } int qrange(node *segment_tree, int x, int y) { int ans = 0; while (top[x] != top[y]) { if (dep[top[x]] < dep[top[y]]) { swap(x, y); } ans ^= query(segment_tree, 1, id[top[x]], id[x]); x = fa[top[x]]; } if (dep[x] > dep[y]) swap(x, y); ans ^= query(segment_tree, 1, id[x], id[y]); return ans; } int main() { // freopen("D:\\common_text\\code_stream\\in.txt","r",stdin); // freopen("D:\\common_text\\code_stream\\out.txt","w",stdout); n = readint(); m = readint(); repd(i, 1, n) { a[i] = readint(); } int u, v; repd(i, 2, n) { u = readint(); v = readint(); // cin >> u >> v; son[u].pb(v); son[v].pb(u); } root = 1; dfs1(root, 0, 1); dfs2(root, root); // build(1, 1, n); int op, x, y; build(A, 1, 1, n); build(B, 1, 1, n); repd(i, 1, n) { if (dep[i] & 1) { modify(A, 1, id[i], a[i]); } else { modify(B, 1, id[i], a[i]); } } while (m--) { op = readint(); x = readint(); y = readint(); if (op == 1) { if (dep[x] & 1) { modify(A, 1, id[x], y); } else { modify(B, 1, id[x], y); } } else if (op == 2) { int d = dist(x, y); int ans = 0; if (d & 1) { ans = qrange(A, x, y)^qrange(B, x, y); } else { if (dep[x] & 1) { ans = qrange(B, x, y) ; } else { ans = qrange(A, x, y); } } printf("%d\n", ans ); } } return 0; }