ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

CH 4913 Fotile模拟赛L (可持久化trie std)

2021-05-14 22:03:09  阅读:208  来源: 互联网

标签:std CH xor Fotile trie 可以 int 持久 latest


摘要

给定序列, 若干个询问, 给定 \(l,r\), 求 \(a[i]\) \(xor\) \(a[i+1]\) \(xor\) \(···\) \(xor\) \(a[j]\) (\(l<=i<=j<=r\)) 的最小值

先假设一个问题: 求 \(a[i]\) \(xor\) \(a[j]\) 的最大值
我们用分块+可持久化 \(trie\) 可以解决:
定义数组 \(f[i][j]\) 表示 \(l[i]\)~\(j\) 的上式最大值, 这里可以用可持久化 \(trie\) 求出, 即 \(query(l[i],root[y],a[j])\) 与 \(f[i][j-1]\) 取 \(max\), 可以理解为在 \(l[i]\)~\(j-1\) 的范围内每两个数字都考虑了 \(xor\), 扩展的点需要和区间所有的数考虑一次使得 \(l[i]\)~\(j\) 中每两个数字都考虑过了 \(xor\), 后得出最大值.
于是先预处理每一个 \(1<=i<=c\) 的 \(f[i][l[i]\)~\(n]\), 查询的时候找到大于等于 \(x\) 的最近的块起始界(当然 \(x.y\) 位于一个块内时需要额外考虑), 于是可以直接查询到 \(l[u]\)~\(y\) 中的所有数经过 \(xor\) 考虑后得出的最大值, 若要扩展到 \(x\)~\(y\), 则只需依次考虑下标为 \(x\)~\(l[u]-1\) 的数与区间每一个数的 \(xor\) 即可. 由于 \(xor\) 满足交换律, 故相反的所有位于 \(l[u]\)~\(y\) 的数同时也都考虑了与前面零碎的数的 \(xor\).
在此期间, 考虑 \(xor\) 用可持久化 \(trie\), 无论区间长短, 查询复杂度只有 \(O(log\) \(INF\)\()\)
对于此题, 求前缀 \(xor\) 和就可以将问题化为以上问题. 但是化为前缀和后, 备选域需要多考虑一下, 因为要得到 \(l\)~\(r\) 是用 \(s[r]-s[l-1]\)

exp

  • 可以看见在此处左边界是固定的几个, 而右边界是可以随意查到的. 也就是在查询时只用考虑左边的零碎部分, 本题可以有这个方便是因为本题的零碎部分信息的朴素获取不需要依据区间内统计的数据. 举个例子, 众数.奇偶性的判断需要依赖于块内统计的该数的个数, 这需要空间来维护, 但是本题的 \(xor\) 结果不需要, 在 \(trie\) 的预处理之后就可以直接查询. 故众数等类型的分块题需要考虑两边零碎(当然若用二分下标求个数也可以只考虑一边, 但显然复杂度会多一个 \(log\)).
  • 可持久化 \(trie\) 有一个数组叫 \(latest\), 非递归就可以维护, 不需要取 \(max\), 因为一般都是顺序添加新时间点, 每一个节点的 \(latest\) 放本时间点即可. 但是十分重要的一点(尤其对于涉及 \(l=0\) 的情形): latest[0]=-1. 因为当一个节点不存在时其 \(latest\) 为 \(0\), 当 \(l\) 为 \(0\) 就会误判此点存在, 当然多判一个 \(trie[p]\) 也可以避免.
  • 块数分为 \(sqrt(m)\) 并非谬误, 均衡考虑一下预处理和查询的时间复杂度即可得到.

代码

#include<cstdio>
#include<cmath>
#include<algorithm>
#define ifor(i,a,b) for(int i=(a);i<=(b);++i)

using namespace std;
const int N=1e4+2e3+5;
int n,m,tot,a[N],p[N],f[100][N],l[100],r[100],
	root[N],trie[N*50][2],latest[N*50];

inline void insert(int p,int q,int val,int id)
{
	for(int k=30;k>=-1;k--)
	{
		latest[q]=id;
		if(k<0)
			break;
		int c=(val>>k)&1;
		trie[q][c^1]=trie[p][c^1];
		trie[q][c]=++tot;
		p=trie[p][c],q=trie[q][c];
	}
}

inline int query1(int l,int q,int val)
{
	int res=0;
	for(int k=30;k>=0;k--)
	{
		int c=(val>>k)&1;
		if(latest[trie[q][c^1]]>=l)
			res|=(1<<k),q=trie[q][c^1];
		else q=trie[q][c];
	}
	return res;
}

inline int query2(int x,int y)
{
	int u=p[x],v=p[y];
	if(u==v)
	{
		int ans=0;
		ifor(i,x,y)
			ans=max(ans,query1(x-1,root[y],a[i]));
		return ans;
	}
	++u;
	int ans=f[u][y];
	ifor(i,x-1,l[u]-2)
		ans=max(ans,query1(x-1,root[y],a[i]));
	return ans;
}

int main()
{
	//freopen("in.txt","r",stdin);
	scanf("%d%d",&n,&m);
	ifor(i,1,n)
		scanf("%d",&a[i]),a[i]^=a[i-1];//!!
	int c=sqrt((double)m);
	c=c>n?n:c;
	int len=n/c;
	ifor(i,1,c)
		l[i]=(i-1)*len+1,r[i]=i*len;
	if(r[c]<n)
		l[c+1]=r[c]+1,r[++c]=n;
	ifor(i,1,c)
		ifor(j,l[i],r[i])
			p[j]=i;
	root[0]=++tot;
	latest[0]=-1;
	insert(0,root[0],0,0);
	ifor(i,1,n)
		root[i]=++tot,
		insert(root[i-1],root[i],a[i],i);
	ifor(i,1,c)
		ifor(j,l[i],n)//!!
			f[i][j]=max(f[i][j-1],query1(l[i]-1,root[j-1],a[j]));
	long long L,R,pre=0;
	ifor(i,1,m)
	{
		scanf("%lld%lld",&L,&R);
		L=(L+pre)%n+1,R=(R+pre)%n+1;
		if(L>R)
			swap(L,R);
		printf("%d\n",pre=query2(L,R));
	}
}

标签:std,CH,xor,Fotile,trie,可以,int,持久,latest
来源: https://www.cnblogs.com/cs-fil/p/14770020.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有