博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
hdu6191(树上启发式合并)
阅读量:6542 次
发布时间:2019-06-24

本文共 3248 字,大约阅读时间需要 10 分钟。

题意

给你一棵带点权的树,每次查询 \(u\)\(x\) ,求以 \(u\) 为根结点的子树上的结点与 \(x\) 异或后最大的结果。

分析

看到子树,直接上树上启发式合并,看到异或,上 \(Trie\)

这道题就是两个经典的题目结合了一波。

树上启发式合并处理这种需要查询整个子树的题目尤其有用,可以复用大量的信息。

离线查询后,到要查询的结点直接在 \(Trie\) \(01\) 树上跑一下即可。

先去理解一波 树上启发式合并(\(dsu \ on \ tree\)),就会发现这真是一道模板题

code

#include
using namespace std;typedef long long ll;const int MAXN = 1e5 + 100;const int MX = 30;struct Ex { int id, x;};struct Trie { int val[MAXN * 30], nxt[MAXN * 30][2], L, root; int newnode() { memset(nxt[L], -1, sizeof nxt[L]); return L++; } void init() { L = 0; root = newnode(); } void update(int x, int key) { int now = root; for(int i = MX; i >= 0; i--) { int o = (x >> i) & 1; if(nxt[now][o] == -1) nxt[now][o] = newnode(); now = nxt[now][o]; val[now] += key; } } int query(int x) { int res = 0; int now = root; for(int i = MX; i >= 0; i--) { int o = (x >> i) & 1; if(val[nxt[now][!o]]) { now = nxt[now][!o]; res |= (1 << i); } else { now = nxt[now][o]; } } return res; }}trie;vector
ex[MAXN];int fa[MAXN], son[MAXN], dep[MAXN], siz[MAXN];int col[MAXN];int cnt, head[MAXN];struct Edge { int to, next;}e[MAXN << 1];void addedge(int u, int v) { e[cnt].to = v; e[cnt].next = head[u]; head[u] = cnt++;}void dfs(int u) { siz[u] = 1; son[u] = 0; for(int i = head[u]; ~i; i = e[i].next) { if(e[i].to != fa[u]) { fa[e[i].to] = u; dep[e[i].to] = dep[u] + 1; dfs(e[i].to); if(siz[e[i].to] > siz[son[u]]) son[u] = e[i].to; siz[u] += siz[e[i].to]; } }}int n, q;int vis[MAXN];int ans[MAXN];void update(int u, int key) { trie.update(col[u], key); for(int i = head[u]; ~i; i = e[i].next) { if(e[i].to != fa[u] && !vis[e[i].to]) update(e[i].to, key); }}void dfs1(int u, int flg) { for(int i = head[u]; ~i; i = e[i].next) { if(e[i].to != fa[u] && e[i].to != son[u]) dfs1(e[i].to, 1); } if(son[u]) { dfs1(son[u], 0); vis[son[u]] = 1; } update(u, 1); for(int i = 0; i < ex[u].size(); i++) { ans[ex[u][i].id] = trie.query(ex[u][i].x); } if(son[u]) vis[son[u]] = 0; if(flg) { update(u, -1); }}int main() { while(~scanf("%d%d", &n, &q)) { for(int i = 1; i <= n; i++) { ex[i].clear(); fa[i] = son[i] = dep[i] = siz[i] = 0; } memset(vis, 0, sizeof vis); memset(ans, 0, sizeof ans); trie.init(); cnt = 0; memset(head, -1, sizeof head); for(int i = 1; i <= n; i++) { scanf("%d", &col[i]); } for(int i = 2; i <= n; i++) { int u; scanf("%d", &u); addedge(u, i); addedge(i, u); } for(int i = 0; i < q; i++) { int u, x; scanf("%d%d", &u, &x); ex[u].push_back(Ex{i, x}); } dfs(1); dfs1(1, -1); for(int i = 0; i < q; i++) { printf("%d\n", ans[i]); } } return 0;}

转载于:https://www.cnblogs.com/ftae/p/7459839.html

你可能感兴趣的文章
NIO框架入门(四):Android与MINA2、Netty4的跨平台UDP双向通信实战
查看>>
架构师速成-架构目标之伸缩性\安全性
查看>>
有向图的拓扑排序算法JAVA实现
查看>>
Nginx配置中的log_format用法梳理(设置详细的日志格式)
查看>>
Zeppelin Prefix not found.
查看>>
linux 的网络设置
查看>>
首届“欧亚杯”象翻棋全国团体邀请赛圆满收评!
查看>>
编译tomcat
查看>>
oracle-xe手工创建数据库
查看>>
UG中卸载被占用的DLL
查看>>
eclipse 设置注释模板详解,与导入模板方法介绍总结
查看>>
Cocos2d-x3.2 文字显示
查看>>
特此说明
查看>>
poj3262
查看>>
python的string操作总结
查看>>
如何把word中的图片怎么导出来呢?
查看>>
ubuntu samba服务器多用户配置【转】
查看>>
母线的种类与作用是什么(转)
查看>>
【Xamarin 挖墙脚系列:IOS 开发界面的3种方式】
查看>>
Atitit.工作流系统的本质是dsl 图形化的dsl 4gl
查看>>