L - 郭大侠与苦恼
题目简单,就是给你一棵树,然后问异或值为0的简单路径有多少条
好难,好麻烦,想了好久才想明白
按dfs的顺序来map+启发式合并,
后来想找个题的大概框架和树形01背包相似,都是用dfs来实现的,只不过树形01背包dfs后的过程是背包的合并,这个是map的合并,还是启发式合并(就是把size小的合并到size大的上),
然后我们这里维护的是pre[u],就是从根节点到u的简单路径异或和,
u到v的简单路径异或和就是pre[u]^pre[v]^lca(u,v)
对于一个dfs,根节点的map维护之前遍历过的子树的每个异或值的个数,然后当前的儿子节点继续往下dfs,在回溯到这里的时候,这个节点上的map就已经维护好了以它为根的各个异或值的个数,然后我们就统计就好了,选择一个size小的进行遍历,对于每个值x,查询x^now(now代表当前的这个根节点,就是他们的最近公共祖先)在另一个map中出现的次数,然后查询完了之后,合并,如果根节点的size比儿子节点的size大,就先交换一下,再合并,就好了
总之就是dfs的框架思路和树形01背包的框架思路是一样的,我感觉,就是在dfs的的过程中维护它就好,维护一个之前已经遍历完的,和这个节点dfs之后回溯回来的,把这两个合并到一起就行
代码:
#include <iostream> #include <cstdio> #include <cstdlib> #include <cstring> #include <cmath> #include <vector> #include <map> #include <algorithm> using namespace std; #define ll long long #define maxn 100005 int n, idx[maxn]; bool vis[maxn]; vector<int> tree[maxn]; map<int, int> XOR[maxn];//记录以该节点为根的子树的各个异或值的计数 ll ans = 0; void dfs_print(int now) { vis[now] = 1; for (int i = 0; i < tree[now].size(); ++i) { if (vis[tree[now][i]]) continue; printf("%d %d\n", now, tree[now][i]); dfs_print(tree[now][i]); } } void dfs(int now, int value) { vis[now] = 1; ++XOR[now][value]; //printf("every %d %d\n", now, value); for (int i = 0; i < tree[now].size(); ++i) { int tmp = tree[now][i]; if (!vis[tmp]) { dfs(tmp, value^tmp); if (XOR[now].size() < XOR[tmp].size())//统计当前子树和根节点及之前所有子树异或值相同的个数 { for (map<int, int>::iterator itor = XOR[now].begin(); itor != XOR[now].end(); ++itor) { if (XOR[tmp].find(now ^ (itor->first)) != XOR[tmp].end()) ans += (itor->second)*XOR[tmp][now ^ (itor->first)]; } XOR[now].swap(XOR[tmp]); } else { for (map<int, int>::iterator itor = XOR[tmp].begin(); itor != XOR[tmp].end(); ++itor) { if (XOR[now].find(now ^ (itor->first)) != XOR[now].end()) ans += (itor->second)*XOR[now][now ^ (itor->first)]; } } //把子树并入到它的父节点中 for (map<int, int>::iterator itor = XOR[tmp].begin(); itor != XOR[tmp].end(); ++itor) { XOR[now][itor->first] += itor->second; } /*for (map<int, int>::iterator itor = XOR[now].begin(); itor != XOR[now].end(); ++itor) printf("%d %d\n", itor->first, itor->second); printf("%d %d ans %lld\n", now, tmp, ans);*/ } } } int main() { //freopen("input.txt", "r", stdin); scanf("%d", &n); int u, v; for (int i = 0; i < n - 1; ++i) { scanf("%d%d", &u, &v); tree[u].push_back(v); tree[v].push_back(u); } /*dfs_print(1); printf("ssssssssssss\n"); memset(vis, 0, sizeof(vis));*/ dfs(1, 1); printf("%lld\n", ans); //system("pause"); //while (1); return 0; }