#可持久化01trie,树链剖分#洛谷 4592 异或

本文介绍了一种利用树剖与01 Trie解决特定树形数据结构问题的方法,通过对树进行预处理,实现快速查询节点子树及路径上的最大异或值,适用于竞赛编程中的复杂查询场景。

题目

现在有一颗以1为根节点的由nnn个节点组成的树,树上每个节点上都有一个权值viv_ivi​。现在有QQQ次操作,操作如下:

111 xxx yyy:查询节点xxx的子树中与yyy异或结果的最大值
2 xxx yyy zzz:查询路径xxxyyy上点与zzz异或结果最大值


分析

这道题有两种操作,所以要分成两个可持久化01trie分别求解,其它其实有点类似最大异或和那道题,然而还要求LCA所以我就写了个树剖


代码

#include <cstdio>
#include <cctype>
#define rr register
using namespace std;
const int N=100101;
struct node{int y,next;}e[N<<1];
int ls[N],rt1[N],rt2[N],tot,k=1,n,q,top[N],dfn[N],son[N],dep[N],a[N],fat[N],big[N];
inline signed iut(){
    rr int ans=0; rr char c=getchar();
    while (!isdigit(c)) c=getchar();
    while (isdigit(c)) ans=(ans<<3)+(ans<<1)+(c^48),c=getchar();
    return ans;
}
inline void print(int ans){
    if (ans>9) print(ans/10);
    putchar(ans%10+48);
}
struct Trie{
    int cnt[N<<6],trie[N<<6][2],tot;
    inline void Insert(int &rt,int x,int now){
        trie[++tot][0]=trie[rt][0],trie[tot][1]=trie[rt][1],cnt[tot]=cnt[rt]+1,rt=tot;
        if (~now) Insert(trie[rt][(x>>now)&1],x,now-1);
    }
    inline signed query(int rt,int hs,int x,int now){
        if (now==-1) return 0;
        rr int p=((x>>now)&1)^1;
        return cnt[trie[rt][p]]^cnt[trie[hs][p]]?query(trie[rt][p],trie[hs][p],x,now-1)|(1<<now):query(trie[rt][p^1],trie[hs][p^1],x,now-1); 
    }
}Tre;
inline void dfs1(int x,int fa){
	dep[x]=dep[fa]+1,fat[x]=fa,son[x]=1;
	for (rr int i=ls[x],mson=-1;i;i=e[i].next)
	if (e[i].y!=fa){
		dfs1(e[i].y,x);
		son[x]+=son[e[i].y];
		if (son[e[i].y]>mson) big[x]=e[i].y,mson=son[e[i].y];
	}
}
inline void dfs2(int x,int linp){
	dfn[x]=++tot,top[x]=linp;
    Tre.Insert(rt1[tot]=rt1[tot-1],a[x],29);
    Tre.Insert(rt2[x]=rt2[fat[x]],a[x],29);
	if (!big[x]) return; dfs2(big[x],linp);
	for (rr int i=ls[x];i;i=e[i].next)
	if (e[i].y!=fat[x]&&e[i].y!=big[x])
	    dfs2(e[i].y,e[i].y);
}
inline signed lca(int x,int y){
	while (top[x]!=top[y]){
		if (dep[top[x]]<dep[top[y]]) x^=y,y^=x,x^=y;
		x=fat[top[x]];
	}
	if (dep[x]>dep[y]) x^=y,y^=x,x^=y;
	return x;
}
inline signed max(int a,int b){return a>b?a:b;}
signed main(){
    n=iut(); q=iut(); Tre.tot=0;
    for (rr int i=1;i<=n;++i) a[i]=iut();
    for (rr int i=1;i<n;++i){
        rr int x=iut(),y=iut();
        e[++k]=(node){y,ls[x]},ls[x]=k,
        e[++k]=(node){x,ls[y]},ls[y]=k;
    }
    dfs1(1,0),dfs2(1,1);
    for (rr int i=1;i<=q;++i){
        rr int opt=iut(),x=iut(),y=iut();
        if (opt&1) print(Tre.query(rt1[dfn[x]+son[x]-1],rt1[dfn[x]-1],y,29));
            else{
                rr int z=iut(),Lca=lca(x,y);
                print(max(Tre.query(rt2[x],rt2[fat[Lca]],z,29),Tre.query(rt2[y],rt2[fat[Lca]],z,29)));
            }
        putchar(10);
    }
    return 0;
}
洛谷P4592 WA了,求原因:#include <bits/stdc++.h> using namespace std; const int BITS = 32; const int MAX_N = 1e5 + 50; int n, q, val[MAX_N], fa[MAX_N], tim; int dep[MAX_N], siz[MAX_N], son[MAX_N]; int top[MAX_N], dfn[MAX_N], rev[MAX_N]; vector<int> e[MAX_N]; void dfs1(int u, int father, int depth) { fa[u] = father; dep[u] = depth; siz[u] = 1; for (int v : e[u]) { if (v == father) continue; dfs1(v, u, depth + 1); siz[u] += siz[v]; if (siz[v] > siz[son[u]]) son[u] = v; } } void dfs2(int u, int topf) { top[u] = topf; dfn[u] = ++tim; rev[tim] = u; if (son[u]) dfs2(son[u], topf); for (int v : e[u]) if (!dfn[v]) dfs2(v, v); } int root[MAX_N], tot; struct Node { int ch[2], cnt; Node() {ch[0] = ch[1] = cnt = 0; } } tr[MAX_N * BITS]; int insert(int pos, int x, int k) { int cur = ++tot, t = x >> k & 1; tr[cur] = tr[pos], tr[cur].cnt++; if (k < 0) return cur; tr[cur].ch[t] = insert(tr[cur].ch[t], x, k - 1); return cur; } int query(int u, int v, int x, int k) { if (k < 0) return 0; int t = x >> k & 1; if (tr[tr[v].ch[t ^ 1]].cnt - tr[tr[u].ch[t ^ 1]].cnt) return query(tr[u].ch[t ^ 1], tr[v].ch[t ^ 1], x, k - 1) + (1 << k); return query(tr[u].ch[t], tr[v].ch[t], x, k - 1); } int query(int l, int r, int x) { return query(root[l - 1], root[r], x, BITS - 1); } int tree_query(int x, int z) { return query(dfn[x], dfn[x] + siz[x] - 1, z); } int path_query(int x, int y, int z) { int ans = 0; while (top[x] != top[y]) { if (dep[top[x]] < dep[top[y]]) swap(x, y); ans = max(ans, query(dfn[top[x]], dfn[x], z)); x = fa[top[x]]; } if (dep[x] < dep[y]) swap(x, y); ans = max(ans, query(dfn[y], dfn[x], z)); return ans; } int main() { cin >> n >> q; for (int i = 1; i <= n; i++) cin >> val[i]; for (int i = 1, u, v; i < n; i++) { cin >> u >> v; e[u].push_back(v); e[v].push_back(u); } dfs1(1, 0, 1); dfs2(1, 1); for (int i = 1; i <= n; i++) root[i] = insert(root[i - 1], val[rev[i]], BITS - 1); for (int opt, x, y, z; q--; ) { cin >> opt; if (opt == 1) { cin >> x >> z; cout << tree_query(x, z) << &#39;\n&#39;; } else { cin >> x >> y >> z; cout << path_query(x, y, z) << &#39;\n&#39;; } } return 0; }
07-19
洛谷P4592,请分析一下这段代码WA40pts的原因: #include <bits/stdc++.h> using namespace std; const int BITS = 32; const int MAX_N = 1e5 + 50; int n, q, val[MAX_N], fa[MAX_N], tim; int dep[MAX_N], siz[MAX_N], son[MAX_N]; int top[MAX_N], dfn[MAX_N], rev[MAX_N]; vector<int> e[MAX_N]; void dfs1(int u, int father, int depth) { fa[u] = father; dep[u] = depth; siz[u] = 1; for (int v : e[u]) { if (v == father) continue; dfs1(v, u, depth + 1); siz[u] += siz[v]; if (siz[v] > siz[son[u]]) son[u] = v; } } void dfs2(int u, int topf) { top[u] = topf; dfn[u] = ++tim; rev[tim] = u; if (son[u]) dfs2(son[u], topf); for (int v : e[u]) if (!dfn[v]) dfs2(v, v); } int root[MAX_N], tot; struct Node { int ch[2], cnt; Node() {ch[0] = ch[1] = cnt = 0; } } tr[MAX_N * BITS]; int insert(int pos, int x, int k) { int cur = ++tot, t = x >> k & 1; tr[cur] = tr[pos], tr[cur].cnt++; if (k < 0) return cur; tr[cur].ch[t] = insert(tr[cur].ch[t], x, k - 1); return cur; } int query(int u, int v, int x, int k) { if (k < 0) return 0; int t = x >> k & 1; if (tr[tr[v].ch[t ^ 1]].cnt - tr[tr[u].ch[t ^ 1]].cnt) return query(tr[u].ch[t ^ 1], tr[v].ch[t ^ 1], x, k - 1) + (1 << k); return query(tr[u].ch[t], tr[v].ch[t], x, k - 1); } int query(int l, int r, int x) { return query(root[l - 1], root[r], x, BITS - 1); } int tree_query(int x, int z) { return query(dfn[x], dfn[x] + siz[x] - 1, z); } int path_query(int x, int y, int z) { int ans = 0; while (top[x] != top[y]) { if (dep[top[x]] < dep[top[y]]) swap(x, y); ans = max(ans, query(dfn[top[x]], dfn[x], z)); x = fa[top[x]]; } if (dep[x] < dep[y]) swap(x, y); ans = max(ans, query(dfn[y], dfn[x], z)); return ans; } int main() { cin >> n >> q; for (int i = 1; i <= n; i++) cin >> val[i]; for (int i = 1, u, v; i < n; i++) { cin >> u >> v; e[u].push_back(v); e[v].push_back(u); } dfs1(1, 0, 1); dfs2(1, 1); for (int i = 1; i <= n; i++) root[i] = insert(root[i - 1], val[rev[i]], BITS - 1); for (int opt, x, y, z; q--; ) { cin >> opt; if (opt == 1) { cin >> x >> z; cout << tree_query(x, z) << &#39;\n&#39;; } else { cin >> x >> y >> z; cout << path_query(x, y, z) << &#39;\n&#39;; } } return 0; }
最新发布
07-24
洛谷P4592WA40pts,分析一下原因: #include <bits/stdc++.h> using namespace std; const int BITS = 32; const int MAX_N = 1e5 + 50; int n, q, val[MAX_N], fa[MAX_N], tim; int dep[MAX_N], siz[MAX_N], son[MAX_N]; int top[MAX_N], dfn[MAX_N], rev[MAX_N]; vector e[MAX_N]; void dfs1(int u, int father, int depth) { fa[u] = father; dep[u] = depth; siz[u] = 1; for (int v : e[u]) { if (v == father) continue; dfs1(v, u, depth + 1); siz[u] += siz[v]; if (siz[v] > siz[son[u]]) son[u] = v; } } void dfs2(int u, int topf) { top[u] = topf; dfn[u] = ++tim; rev[tim] = u; if (son[u]) dfs2(son[u], topf); for (int v : e[u]) if (!dfn[v]) dfs2(v, v); } int root[MAX_N], tot; struct Node { int ch[2], cnt; Node() {ch[0] = ch[1] = cnt = 0; } } tr[MAX_N * BITS]; int insert(int pos, int x, int k) { int cur = tot, t = x >> k & 1; tr[cur] = tr[pos], tr[cur].cnt++; if (k < 0) return cur; tr[cur].ch[t] = insert(tr[cur].ch[t], x, k - 1); return cur; } int query(int u, int v, int x, int k) { if (k < 0) return 0; int t = x >> k & 1; if (tr[tr[v].ch[t ^ 1]].cnt - tr[tr[u].ch[t ^ 1]].cnt) return query(tr[u].ch[t ^ 1], tr[v].ch[t ^ 1], x, k - 1) + (1 << k); return query(tr[u].ch[t], tr[v].ch[t], x, k - 1); } int query(int l, int r, int x) { return query(root[l - 1], root[r], x, BITS - 1); } int tree_query(int x, int z) { return query(dfn[x], dfn[x] + siz[x] - 1, z); } int path_query(int x, int y, int z) { int ans = 0; while (top[x] != top[y]) { if (dep[top[x]] < dep[top[y]]) swap(x, y); ans = max(ans, query(dfn[top[x]], dfn[x], z)); x = fa[top[x]]; } if (dep[x] < dep[y]) swap(x, y); ans = max(ans, query(dfn[y], dfn[x], z)); return ans; } int main() { cin >> n >> q; for (int i = 1; i <= n; i++) cin >> val[i]; for (int i = 1, u, v; i < n; i++) { cin >> u >> v; e[u].push_back(v); e[v].push_back(u); } dfs1(1, 0, 1); dfs2(1, 1); for (int i = 1; i <= n; i++) root[i] = insert(root[i - 1], val[rev[i]], BITS - 1); for (int opt, x, y, z; q–; ) { cin >> opt; if (opt == 1) { cin >> x >> z; cout << tree_query(x, z) << ‘\n’; } else { cin >> x >> y >> z; cout << path_query(x, y, z) << ‘\n’; } } return 0; }
07-24
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值