因为省选 \(Day2T2\) 来学习 \(01\ trie\) 合并……
首先和线段树合并还有左偏树的 \(merge\) 一样的,就是一个 \(merge\) 函数
inline int merge(int x,int y)
{
if(!x||!y) return x+y;
int p=++tot;
for(int i=0;i<=25;++i) ch[p][i]=merge(ch[x][i],ch[y][i]);
return p;
}
然后就实现了 \(trie\) 树的合并(啊不是 \(01\ trie\))
然后是一个应用题:
\(CF778C\)
可以在一棵 \(trie\) 树上面删除一层的边,剩下的子树如果可以就像普通 \(trie\) 一样合并
求删掉哪一层剩下的点最少
这题的贡献法不太好想
删掉哪层剩下的点最少,那就考虑删掉的点最多的一层
考虑一下合并的过程我们会新开节点,如果新开一个相当于有一个被删掉了
然后就可以从上到下 \(dfs\) 处理这个过程了
接着是省选题:
P6623 [省选联考 2020 A 卷] 树
其实不一定是 \(01\ trie\) 合并做?
简述题意:
实现一个支持区间加 \(1\) ,区间异或和的数据结构、
其实难点在区间加一
然后如果在 \(trie\) 上面做就是交换左右儿子
(正好学了个板子……)
#include
using namespace std;
#define int long long
namespace yspm{
inline int read()
{
int res=0,f=1; char k;
while(!isdigit(k=getchar())) if(k=='-') f=-1;
while(isdigit(k)) res=res*10+k-'0',k=getchar();
return res*f;
}
const int N=54e4;
int n,ans,res[N],v[N];
vector g[N];
int tot,cnt[N*20],val[N*20],dep[N*20],ls[N*20],rs[N*20],rt[N],fa[N];
inline void push_up(int x){val[x]=val[ls[x]]^val[rs[x]]^((cnt[rs[x]]&1)<20) return ;
add(rs[p]); swap(rs[p],ls[p]);
push_up(p);
}
inline void insert(int &p,int val,int d)
{
if(!p) p=++tot,dep[p]=d;
++cnt[p]; if(d>20) return ;
if((val>>d)&1) insert(rs[p],val,d+1);
else insert(ls[p],val,d+1);
return push_up(p);
}
inline void dfs(int x)
{
int siz=g[x].size();
for(int i=0;i