Skip to content

Commit

Permalink
style: format markdown files with remark-lint
Browse files Browse the repository at this point in the history
  • Loading branch information
24OI-bot committed Dec 12, 2018
1 parent e12789a commit 374acd1
Showing 1 changed file with 65 additions and 68 deletions.
133 changes: 65 additions & 68 deletions docs/ds/persistent-trie.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@

对一个长度为 $n$ 的数组 $a$ 维护以下操作:

1. 在数组的末尾添加一个数 $x$ ,数组的长度 $n$ 自增 $1$ 。
1. 在数组的末尾添加一个数 $x$ ,数组的长度 $n$ 自增 $1$ 。

2. 给出查询区间 $[l,r]$ 和一个值 $k$ ,求当 $l\le p\le r$ 时, $k \oplus \bigoplus^{n}_{i=p} a_i$ 。
2. 给出查询区间 $[l,r]$ 和一个值 $k$ ,求当 $l\le p\le r$ 时, $k \oplus \bigoplus^{n}_{i=p} a_i$ 。

这个求的值可能有些麻烦,利用常用的处理连续异或的方法,记 $s_x=\bigoplus_{i=1}^x a_i$ ,则原式等价于 $s_{p-1}\oplus s_n\oplus k$ ,观察到 $s_n \oplus k$ 在查询的过程中是固定的,题目的查询变化为查询在区间 $[l-1,r-1]$ 中异或定值( $s_n\oplus k$ )的最大值。

Expand All @@ -17,73 +17,70 @@
查询区间,只需要利用前缀和和差分的思想,用两棵前缀 Trie 树(也就是按顺序添加数的两个历史版本)相减即为该区间的线段树。再利用动态开点的思想,不添加没有计算过的点,以减少空间占用。

```cpp
#include<cstdio>
#include<cstring>
#include<algorithm>
#include <algorithm>
#include <cstdio>
#include <cstring>
using namespace std;
const int maxn=600010;
int n,q,a[maxn],s[maxn],l,r,x;
const int maxn = 600010;
int n, q, a[maxn], s[maxn], l, r, x;
char op;
struct Trie
{
int cnt,rt[maxn],ch[maxn*33][2],val[maxn*33];
void insert(int o,int lst,int v)
{
for(int i=28;i>=0;i--)
{
val[o]=val[lst]+1;//在原版本的基础上更新
if((v&(1<<i))==0)
{
if(!ch[o][0])ch[o][0]=++cnt;
ch[o][1]=ch[lst][1];
o=ch[o][0];lst=ch[lst][0];
}
else
{
if(!ch[o][1])ch[o][1]=++cnt;
ch[o][0]=ch[lst][0];
o=ch[o][1];lst=ch[lst][1];
}
}
val[o]=val[lst]+1;
//printf("%d\n",o);
}
int query(int o1,int o2,int v)
{
int ret=0;
for(int i=28;i>=0;i--)
{
//printf("%d %d %d\n",o1,o2,val[o1]-val[o2]);
int t=((v&(1<<i))?1:0);
if(val[ch[o1][!t]]-val[ch[o2][!t]])ret+=(1<<i),o1=ch[o1][!t],o2=ch[o2][!t];//尽量向不同的地方跳
else o1=ch[o1][t],o2=ch[o2][t];
}
return ret;
}
}st;
int main()
{
scanf("%d%d",&n,&q);
for(int i=1;i<=n;i++)scanf("%d",a+i),s[i]=s[i-1]^a[i];
for(int i=1;i<=n;i++)st.rt[i]=++st.cnt,st.insert(st.rt[i],st.rt[i-1],s[i]);
while(q--)
{
scanf(" %c",&op);
if(op=='A')
{
n++;
scanf("%d",a+n);
s[n]=s[n-1]^a[n];
st.rt[n]=++st.cnt;
st.insert(st.rt[n],st.rt[n-1],s[n]);
}
if(op=='Q')
{
scanf("%d%d%d",&l,&r,&x);l--;r--;
if(l==r&&l==0)printf("%d\n",s[n]^x);//记得处理 l=r=1 的情况
else printf("%d\n",st.query(st.rt[r],st.rt[max(l-1,0)],x^s[n]));
}
}
return 0;
struct Trie {
int cnt, rt[maxn], ch[maxn * 33][2], val[maxn * 33];
void insert(int o, int lst, int v) {
for (int i = 28; i >= 0; i--) {
val[o] = val[lst] + 1; //在原版本的基础上更新
if ((v & (1 << i)) == 0) {
if (!ch[o][0]) ch[o][0] = ++cnt;
ch[o][1] = ch[lst][1];
o = ch[o][0];
lst = ch[lst][0];
} else {
if (!ch[o][1]) ch[o][1] = ++cnt;
ch[o][0] = ch[lst][0];
o = ch[o][1];
lst = ch[lst][1];
}
}
val[o] = val[lst] + 1;
// printf("%d\n",o);
}
int query(int o1, int o2, int v) {
int ret = 0;
for (int i = 28; i >= 0; i--) {
// printf("%d %d %d\n",o1,o2,val[o1]-val[o2]);
int t = ((v & (1 << i)) ? 1 : 0);
if (val[ch[o1][!t]] - val[ch[o2][!t]])
ret += (1 << i), o1 = ch[o1][!t], o2 = ch[o2][!t]; //尽量向不同的地方跳
else
o1 = ch[o1][t], o2 = ch[o2][t];
}
return ret;
}
} st;
int main() {
scanf("%d%d", &n, &q);
for (int i = 1; i <= n; i++) scanf("%d", a + i), s[i] = s[i - 1] ^ a[i];
for (int i = 1; i <= n; i++)
st.rt[i] = ++st.cnt, st.insert(st.rt[i], st.rt[i - 1], s[i]);
while (q--) {
scanf(" %c", &op);
if (op == 'A') {
n++;
scanf("%d", a + n);
s[n] = s[n - 1] ^ a[n];
st.rt[n] = ++st.cnt;
st.insert(st.rt[n], st.rt[n - 1], s[n]);
}
if (op == 'Q') {
scanf("%d%d%d", &l, &r, &x);
l--;
r--;
if (l == r && l == 0)
printf("%d\n", s[n] ^ x); //记得处理 l=r=1 的情况
else
printf("%d\n", st.query(st.rt[r], st.rt[max(l - 1, 0)], x ^ s[n]));
}
}
return 0;
}
```

0 comments on commit 374acd1

Please sign in to comment.