把博客园图标替换成自己的图标
把博客园图标替换成自己的图标end

【洛谷5795】[THUSC2015] 异或运算(可持久化Trie)

点此看题面

大致题意: 给定一个长度为\(n\)的序列\(x_{1\sim n}\)和一个长度为\(m\)的序列\(y_{1\sim m}\),矩阵\(A\)中第\(i\)行第\(j\)列的元素\(A_{i,j}=x_i\ xor\ y_j\),每次询问矩阵中满足行号\(i∈[u,d]\),列号\(j∈[l,r]\)的子矩阵中第\(k\)大的元素。

两个\(log\)的做法

首先我们可以有一个复杂度较劣的两个\(log\)的做法:二分+可持久化\(Trie\)

考虑对于序列\(y\)建一棵可持久化\(Trie\)

然后,我们二分答案\(mid\)

接着,枚举每一行(注意行数很少),求出对于每一行大于等于\(mid\)的数的个数。

把这些个数加起来,如果大于等于\(k\),说明答案\(mid\)合法,并继续二分更大的答案,否则二分较小的答案。

这个两个\(log\)的做法应该还是比较简单的。

优化做法

\(XZY\)神仙的指导下,我知道了该怎么把这个做法优化为一个\(log\)

我们可以让询问的这些行一起在可持久化\(Trie\)上跑,每一行分别记下当前的对应的节点。

然后从高到低枚举每一位,统计所有行对于这一位所能有的\(1\)的个数。

如果这个个数大于等于\(k\),就说明这一位可以为\(1\),否则,这一位为\(0\)

代码

#include<bits/stdc++.h>
#define Tp template<typename Ty>
#define Ts template<typename Ty,typename... Ar>
#define Reg register
#define RI Reg int
#define Con const
#define CI Con int&
#define I inline
#define W while
#define N 1000
#define M 300000
using namespace std;
int n,m,a[N+5],b[M+5];
class FastIO
{
	private:
		#define FS 100000
		#define tc() (A==B&&(B=(A=FI)+fread(FI,1,FS,stdin),A==B)?EOF:*A++)
		#define tn (x<<3)+(x<<1)
		#define D isdigit(c=tc())
		char c,*A,*B,FI[FS];
	public:
		I FastIO() {A=B=FI;}
		Tp I void read(Ty& x) {x=0;W(!D);W(x=tn+(c&15),D);}
		Ts I void read(Ty& x,Ar&... y) {read(x),read(y...);}
}F;
class ChairmanTrie
{
	private:
		int T;struct node {int Sz;node* S[2];I node() {Sz=0,S[0]=S[1]=NULL;}}*Rt[M+5],*l[N+5],*r[N+5];
		#define Sz(x) (x==NULL?0:x->Sz)
		#define S(x,d) (x==NULL?NULL:x->S[d])
		I void Ins(node*& rt,node* lst,CI x,CI d)//插入
		{
			rt=new node,rt->Sz=Sz(lst),rt->S[0]=S(lst,0),rt->S[1]=S(lst,1);
			if(++rt->Sz,!~d) return;int t=(x>>d)&1;Ins(rt->S[t],S(lst,t),x,d-1);
		}
		I int Qry(CI s,CI t,CI k,CI d)//询问
		{
			if(!~d) return 0;RI i,tot=0;
			for(i=s;i<=t;++i) tot+=Sz(S(r[i],(a[i]>>d)&1^1))-Sz(S(l[i],(a[i]>>d)&1^1));//统计能有的1的个数
			if(tot>=k)//如果个数大于等于k,说明这一位能填1
			{
				for(i=s;i<=t;++i) l[i]=S(l[i],(a[i]>>d)&1^1),r[i]=S(r[i],(a[i]>>d)&1^1);
				return Qry(s,t,k,d-1)|(1<<d);
			}
			else//否则填0
			{
				for(i=s;i<=t;++i) l[i]=S(l[i],(a[i]>>d)&1),r[i]=S(r[i],(a[i]>>d)&1);
				return Qry(s,t,k-tot,d-1);
			}
		}
	public:
		I ChairmanTrie() {for(RI i=1;i<=N;++i) Rt[i]=NULL;}
		I void Ins(CI v,CI v_,CI x) {Ins(Rt[v],Rt[v_],x,30);}
		I int Qry(CI vl,CI vr,CI s,CI t,CI k)
		{
			for(RI i=s;i<=t;++i) l[i]=Rt[vl-1],r[i]=Rt[vr];return Qry(s,t,k,30);//初始化每一行所对应的节点为根节点
		}
}T;
int main()
{
	RI Qt,i,u,d,x,y,k,l,r,mid,t;F.read(n),F.read(m);
	for(i=1;i<=n;++i) F.read(a[i]);for(i=1;i<=m;++i) F.read(b[i]),T.Ins(i,i-1,b[i]);//初始化可持久化Trie
	F.read(Qt);W(Qt--) F.read(u,d,x,y,k),printf("%d\n",T.Qry(x,y,u,d,k));return 0;//处理询问
}
posted @ 2019-12-22 20:37  TheLostWeak  阅读(180)  评论(0编辑  收藏  举报