标签:++ 上进 ase void 空间 can size bit 可持久化trie树
题目分析:
很无聊的一道题目。首先区间内单点对应异或值的询问容易想到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 }
BZOJ5338 [TJOI2018] Xor 【可持久化Trie树】【dfs序】
标签:++ 上进 ase void 空间 can size bit 可持久化trie树
原文地址:https://www.cnblogs.com/Menhera/p/9059869.html