分类简述
一般的trie
并没有什么特别的,可以O(n)进行字符串匹配。
二进制trie
这不是做字符串匹配的,而是查找最大异或和,从高位贪心即可,高位不够补0
可持久化trie
单纯的给trie加个可持久化
权值线段树
二进制trie
注意:
- 充分理解在高层结点决策的思想,因为边才是权值。
- 直接一位对一位,调位置太麻烦了。
- 注意那个bool运算要转换成bool型才用^什么的。
- 写递归结构就可以了。
主席树
权值线段树的可持久化版本咯
代码
可持久化二进制trie
//就决定递归版了
struct TRIE
{
int rt[maxv],np,ch[maxv][2],sz[maxv],val[maxv];
void Build()
{
np=1;rt[0]=1;//因为后面会用到0这个点
memset(rt,0,sizeof(rt));
memset(ch,0,sizeof(ch));
memset(sz,0,sizeof(sz));
memset(val,0,sizeof(val));
}
int Newnode(int pre)
{
++np;
if(pre)
ch[np][0]=ch[pre][0],ch[np][1]=ch[pre][1],sz[np]=sz[pre],val[np]=val[pre];
else
ch[np][0]=ch[np][1]=sz[np]=val[np]=0;
return np;
}
void add(int pre,int &now,int x,int i)
{
now=Newnode(pre);
sz[now]++;
if(i>N)
{
val[now]++;
return;
}
bool id=x&(1<<(N-i));
add(ch[pre][id],ch[now][id],x,i+1);
}
int query(int lnow,int rnow,int x,int i)
{
if(i>N)return 0;
bool id=x&(1<<(N-i));
int ret;
if(sz[ch[rnow][id^1]]-sz[ch[lnow][id^1]])
{
ret=query(ch[lnow][id^1],ch[rnow][id^1],x,i+1);
ret=ret|(1<<(N-i));
}
else
{
ret=query(ch[lnow][id],ch[rnow][id],x,i+1);
ret=ret&(~(1<<(N-i)));
}
return ret;
}
}tri;
区间查询带偏移最大异或和
int DFS(int a,int b,int i)//这里是返回a+x的最优值
{
if(a==b)return a;
int mid=(a+b)>>1;
if( Q & (1<<i) )//第i位为1,那么我们希望a为0
{
if(max(0,a-x)<=min(N,mid-x) && sgt.query(sgt.rt[l-1],sgt.rt[r],0,N,max(0,a-x),min(N,mid-x) ) )
return DFS(a,mid,i-1);
else
return DFS(mid+1,b,i-1);
}
else
{
if(max(0,mid+1-x)<=min(N,b-x) && sgt.query(sgt.rt[l-1],sgt.rt[r],0,N,max(0,mid+1-x),min(N,b-x) ) )
return DFS(mid+1,b,i-1);
else
return DFS(a,mid,i-1);
}
}
int main()
{
Init();
while(m--)
{
scanf("%d%d%d%d",&Q,&x,&l,&r);
printf("%d\n",Q^DFS(0, ( 1<<(oo+1) )-1 , oo ) );
}
return 0;
}