BZOJ5338 [TJOI2018] Xor 【可持久化Trie树】【dfs序】

题目分析:

  很无聊的一道题目。首先区间内单点对应异或值的询问容易想到trie树。由于题目在树上进行,case1将路径分成两段,然后dfs的时候顺便可持久化trie树做询问。case2维护dfs序,对dfs序建可持久化的trie树。这样做的空间复杂度是O(nw),时间复杂度是O(nw).

代码:

  1 #include<bits/stdc++.h>
  2 using namespace std;
  3
  4 const int maxn=102000;
  5
  6 int n,q;
  7 int v[maxn];
  8 vector<int> g[maxn];
  9
 10 vector<pair<int,int> > qy[maxn];
 11 vector<pair<int,int> > vec;
 12
 13 int ans[maxn],num,kd[maxn];
 14 int dep[maxn],dfsin[maxn],dfsout[maxn],fa[maxn];
 15
 16 vector<pair<int,int> > Lca[maxn];
 17 int pre[maxn];
 18
 19 int found(int x){
 20     int rx = x; while(pre[rx] != rx) rx = pre[rx];
 21     while(pre[x] != rx){
 22     int t = pre[x]; pre[x] = rx; x = t;
 23     }
 24     return rx;
 25 }
 26
 27 void dfs(int now,int dp,int f){
 28     dfsin[now] = dfsout[now] = ++num;fa[now] = f; dep[now] = dp;
 29     for(auto pr:Lca[now]){
 30     if(dep[pr.first] == 0) continue;
 31     int la = found(pr.first);
 32     qy[now].push_back(make_pair(la,pr.second));
 33     qy[pr.first].push_back(make_pair(la,pr.second));
 34     }
 35     for(auto i:g[now]){
 36     if(i == f) continue;
 37     dfs(i,dp+1,now);
 38     dfsout[now] = dfsout[i];
 39     }
 40     pre[found(now)] = found(f);
 41 }
 42
 43 void read(){
 44     scanf("%d%d",&n,&q);
 45     for(int i=1;i<=n;i++) scanf("%d",&v[i]);
 46     for(int i=1;i<n;i++){
 47     int x,y; scanf("%d%d",&x,&y);
 48     g[x].push_back(y); g[y].push_back(x);
 49     }
 50     for(int i=1;i<=q;i++){
 51     int cas; scanf("%d",&cas);
 52     if(cas == 1){
 53         int x,y; scanf("%d%d",&x,&y);
 54         vec.push_back(make_pair(x,i));kd[i] = y;
 55     }else{
 56         int x,y,z; scanf("%d%d%d",&x,&y,&z);
 57         Lca[x].push_back(make_pair(y,i));
 58         if(x!=y) Lca[y].push_back(make_pair(x,i));
 59         kd[i] = z;
 60     }
 61     }
 62     for(int i=1;i<=n;i++) pre[i] = i;
 63     dfs(1,1,0);
 64 }
 65
 66 int his[maxn],om;
 67 int sz[maxn*130],ch[maxn*130][2];
 68
 69 void follow(int pt,int last,int dt){
 70     int hbit = 30;
 71     while(hbit!=-1){
 72     if((1<<hbit)&dt){
 73         ch[pt][0] = ch[last][0];
 74         ch[pt][1] = ++num;
 75         pt = num; last = ch[last][1];
 76         sz[pt] = sz[last]+1;
 77     }else{
 78         ch[pt][1] = ch[last][1];
 79         ch[pt][0] = ++num;
 80         pt = num; last = ch[last][0];
 81         sz[pt] = sz[last]+1;
 82     }
 83     hbit--;
 84     }
 85 }
 86
 87 void ins(int now){
 88     int last = his[om-1];
 89     num++;int pt = num; sz[pt] = sz[last]+1;
 90     his[om] = num;
 91     follow(pt,last,v[now]);
 92 }
 93
 94 int query(int now,int last,int z){
 95     now = his[now]; last = his[last];
 96     int hbit = 30;
 97     while(hbit!=-1){
 98     if((1<<hbit)&z){
 99         if(sz[ch[now][0]]-sz[ch[last][0]]){
100         now = ch[now][0];last = ch[last][0];
101         }else{
102         z -= (1<<hbit);now = ch[now][1];last = ch[last][1];
103         }
104     }else{
105         if(sz[ch[now][1]]-sz[ch[last][1]]){
106         z += (1<<hbit);
107         now = ch[now][1];last = ch[last][1];
108         }else{
109         now = ch[now][0];last = ch[last][0];
110         }
111     }
112     hbit--;
113     }
114     return z;
115 }
116
117 void del(int now){his[om] = 0;}
118
119 void dfs2(int now){
120     om++;ins(now);
121     for(auto pr:qy[now]){
122     int last = dep[pr.first]-1,data = kd[pr.second];
123     ans[pr.second] = max(ans[pr.second],query(dep[now],last,data));
124     }
125     for(auto i:g[now]){
126     if(i == fa[now]) continue;
127     dfs2(i);
128     }
129     del(now);om--;
130 }
131
132 void dfs3(int now){
133     om++;ins(now);
134     for(auto i:g[now]){
135     if(i == fa[now]) continue;
136     dfs3(i);
137     }
138 }
139
140 void work(){
141     num = 1;his[0] = 1;
142     dfs2(1);
143     memset(ch,0,sizeof(ch));memset(sz,0,sizeof(sz));
144     num = 1;his[0] = 1;om = 0;
145     dfs3(1);
146     for(auto pr:vec){
147     int st = dfsin[pr.first],ed = dfsout[pr.first];
148     ans[pr.second] = query(ed,st-1,kd[pr.second]);
149     }
150     for(int i=1;i<=q;i++) printf("%d\n",ans[i]);
151 }
152
153 int main(){
154     read();
155     work();
156     return 0;
157 }

原文地址:https://www.cnblogs.com/Menhera/p/9059869.html

时间: 2024-08-27 12:36:56

BZOJ5338 [TJOI2018] Xor 【可持久化Trie树】【dfs序】的相关文章

Tsinsen A1505. 树(张闻涛) 倍增LCA,可持久化线段树,DFS序

题目:http://www.tsinsen.com/A1505 A1505. 树(张闻涛) 时间限制:1.0s   内存限制:512.0MB 总提交次数:196   AC次数:65   平均分:58.62 将本题分享到: 查看未格式化的试题   提交   试题讨论 试题来源 2013中国国家集训队第二次作业 问题描述 给定一棵N个节点的树,每个点有一个权值,有M个询问(a,b,c)若a 为1,回答b到c路径上的最小权值,若a为2,回答b到c路径上的最大权值,若a为3,回答b到c路径上的所有权值的

51nod 1295 XOR key (可持久化Trie树)

1295 XOR key  题目来源: HackerRank 基准时间限制:1.5 秒 空间限制:262144 KB 分值: 160 难度:6级算法题 给出一个长度为N的正整数数组A,再给出Q个查询,每个查询包括3个数,L, R, X (L <= R).求A[L] 至 A[R] 这R - L + 1个数中,与X 进行异或运算(Xor),得到的最大值是多少? Input 第1行:2个数N, Q中间用空格分隔,分别表示数组的长度及查询的数量(1 <= N <= 50000, 1 <= 

【bzoj4212】神牛的养成计划 Trie树+可持久化Trie树

题目描述 Hzwer成功培育出神牛细胞,可最终培育出的生物体却让他大失所望...... 后来,他从某同校女神 牛处知道,原来他培育的细胞发生了基因突变,原先决定神牛特征的基因序列都被破坏了,神牛hzwer很生气,但他知道基因突变的低频性,说不定还有以下优秀基因没有突变,那么他就可以用限制性核酸内切酶把它们切出来,然后再构建基因表达载体什么的,后面你懂的...... 黄学长现在知道了N个细胞的DNA序列,它们是若干个由小写字母组成的字符串.一个优秀的基因是两个字符串s1和s2,当且仅当s1是某序列

【bzoj3281】最大异或和 可持久化Trie树

题目描述 给定一个非负整数序列 {a},初始长度为 N.       有M个操作,有以下两种操作类型:1.A x:添加操作,表示在序列末尾添加一个数 x,序列的长度 N+1.2.Q l r x:询问操作,你需要找到一个位置 p,满足 l<=p<=r,使得:a[p] xor a[p+1] xor ... xor a[N] xor x 最大,输出最大是多少. 输入 第一行包含两个整数 N  ,M,含义如问题描述所示.   第二行包含 N个非负整数,表示初始的序列 A . 接下来 M行,每行描述一个

[bzoj3261]最大异或和[可持久化trie树]

因为要求异或和最大,所以可以考虑从高位开始,向低位枚举尽可能接近~x的值,所以以二进制位为关键字,建立可持久化trie树,根据异或和的性质,XOR_SUM{i,j}=XOR_SUM{1,j} xor XOR_SUM{1,i-1},所以查询问题也可以解决了. 1 #include <iostream> 2 #include <algorithm> 3 #include <cstdio> 4 #include <cstdlib> 5 #include <c

BZOJ 2741【FOTILE模拟赛】L 分块+可持久化Trie树

题目大意 给出一个序列,求[l, r]中的最大连续xor 和. 强制在线 思路 先把整个序列分成n  √  块,预处理每一块的开头到每个数字的最大连续xor 和.这个我们只需处理出前缀xor 和,之后用可持久化Trie树就可以搞定.这样询问的右边就是整块的了.剩下左边的随便暴力一下就能过了.. CODE #define _CRT_SECURE_NO_WARNINGS #include <cmath> #include <cstdio> #include <cstring>

【BZOJ3689】异或之 堆+可持久化Trie树

[BZOJ3689]异或之 Description 给定n个非负整数A[1], A[2], ……, A[n].对于每对(i, j)满足1 <= i < j <= n,得到一个新的数A[i] xor A[j],这样共有n*(n-1)/2个新的数.求这些数(不包含A[i])中前k小的数.注:xor对应于pascal中的“xor”,C++中的“^”. Input 第一行2个正整数 n,k,如题所述.以下n行,每行一个非负整数表示A[i]. Output 共一行k个数,表示前k小的数. Samp

【bzoj3166】[Heoi2013]Alo 可持久化Trie树+STL-set

题目描述 Welcome to ALO ( Arithmetic and Logistic Online).这是一个VR MMORPG ,如名字所见,到处充满了数学的谜题.现在你拥有n颗宝石,每颗宝石有一个能量密度,记为ai,这些宝石的能量密度两两不同.现在你可以选取连续的一些宝石(必须多于一个)进行融合,设为  ai, ai+1, …, a j,则融合而成的宝石的能量密度为这些宝石中能量密度的次大值与其他任意一颗宝石的能量密度按位异或的值,即,设该段宝石能量密度次大值为k,则生成的宝石的能量密

bzoj 3261: 最大异或和 (可持久化trie树)

3261: 最大异或和 Time Limit: 10 Sec  Memory Limit: 512 MB Description 给定一个非负整数序列 {a},初始长度为 N.       有   M个操作,有以下两种操作类型: 1 .A x:添加操作,表示在序列末尾添加一个数 x,序列的长度 N+1.2 .Q l r x:询问操作,你需要找到一个位置 p,满足 l<=p<=r,使得: a[p] xor a[p+1] xor ... xor a[N] xor x 最大,输出最大是多少. Inp