[TJOI2018]异或
link
可持久化Trie初学笔记。今天写可持久化数据结构都写烦了。
可持久化Trie长得和主席树颇有几分神似,都是一排根节点然后下面一堆纵横交错的边相互连接(也是,可持久化数据结构的功能注定了它们只能长成这幅模样)。
说回本题。为了实现可持久化,考虑加入一个字符串可能会对Trie造成什么影响。可以想到对于根节点来说,应该会有一条边连向该字符串的对应字符,而除了这条边以外的所有连边信息都应该从上一个状态(其实任意合法状态都可以)继承下来,为的是不丢失信息(也就是你从这个节点出去仍然能访问到之前的节点)。然后往下跳的同时前面的节点也往下跳,以维护合法性。
题目嘛就是一个模板,树上问题转序列,基本操作。其它便没有什么了。
#include
//#define zczc
const int N=100010;
inline void read(int &wh){
wh=0;int f=1;char w=getchar();
while(w<'0'||w>'9'){if(w=='-')f=-1;w=getchar();}
while(w>='0'&&w<='9'){wh=wh*10+w-'0';w=getchar();}
wh*=f;return;
}
inline void swap(int &s1,int &s2){
int s3=s1;s1=s2;s2=s3;return;
}
inline int max(int s1,int s2){
return s1=0;i--){
int now=((val>>i)&1);
t[y].ch[!now]=t[x].ch[!now];
t[y].ch[now]=++cnt;
y=t[y].ch[now],x=t[x].ch[now];
t[y].data=ti;
}
}
inline int work(int l,int r,int val){
int x=root[r],an=0;
for(int i=30;i>=0;i--){
an<<=1;
int now=((val>>i)&1);
if(t[t[x].ch[!now]].data>=l)an+=1,x=t[x].ch[!now];
else x=t[x].ch[now];
}
return an;
}
inline void print(int x,int val){
if(!x)return;
if(t[x].ch[0]==0&&t[x].ch[1]==0){
printf("%d ",val);return;
}
print(t[x].ch[0],val<<1);
print(t[x].ch[1],val<<1|1);
}
}t1,t2;
struct edge{
int t,next;
}e[N<<1];
int head[N],esum;
inline void add(int fr,int to){
e[++esum]=(edge){to,head[fr]};head[fr]=esum;
}
int dfn,vv[N],id[N],size[N],nxt[N][20],d[N];
void dfs(int wh,int fa){
vv[++dfn]=a[wh];id[wh]=dfn;size[wh]=1;
nxt[wh][0]=fa;d[wh]=d[fa]+1;
for(int i=1;i<20;i++)nxt[wh][i]=nxt[nxt[wh][i-1]][i-1];
t1.insert(t1.root[fa],wh,a[wh]);
for(int i=head[wh],th;i;i=e[i].next){
if((th=e[i].t)==fa)continue;
dfs(th,wh);
size[wh]+=size[th];
}
}
int lca(int s1,int s2){
if(d[s1]=0;i--){
if(d[nxt[s1][i]]>=d[s2])s1=nxt[s1][i];
}
if(s1==s2)return s1;
for(int i=19;i>=0;i--){
if(nxt[s1][i]^nxt[s2][i]){
s1=nxt[s1][i];
s2=nxt[s2][i];
}
}
return nxt[s1][0];
}
signed main(){
#ifdef zczc
freopen("in.txt","r",stdin);
#endif
int s1,s2,s3,op;
read(m);read(n);
for(int i=1;i<=m;i++)read(a[i]);
for(int i=1;i