LGP5795题解

首先 \(k\) 大容易让我们想到 主席树&树套树&整体二分,而异或又让我们想到 01-Trie。

所以就有一个很明显的二分,二分一个 mid 看有多少个数不大于 mid。

然后发现 \(n\) 只有 \(1000\),所以可以暴力枚举第一维度,然后对 \(y\) 建 01-Trie,在 01-Trie 上查询即可,复杂度 \(O(nq\log^2V)\)然而复杂度太高过不去

然而我们发现这个过程和主席树查找 \(k\) 大有点儿像。可是有多棵树啊?

学过 树状数组套权值树 的同学应该知道把根全部存起来,然后二分下去,树套树原本的三只 \(\log\) 就变成了 \(\log^2\)

所以我们在这里也可以将 \(O(n)\) 个根存起来向下二分,感觉有点儿像树套树,又有点儿像整体二分。

最终的复杂度是 \(O(nq\log V)\) 的。

#include<cstdio>
const int M=3e5+5,INF=0x7fffffff;
int n,m,Q,tot,x[1005],y[M],root[M];
int q[1005],p[1005];
struct Node{
	int sum,chi[2];
}t[M*35];
int Modify(int u,int x,int d=30){
	int o=x>>d&1,id=++tot;
	t[id]=t[u];++t[id].sum;
	if(~d)t[id].chi[o]=Modify(t[u].chi[o],x,d-1);
	return id;
}
int Query(int k,int l,int r,int L=0,int R=INF,int d=30){
	if(L==R)return L;
	register int i,o,sum=0,mid=(long long)L+R>>1;
	for(i=l;i<=r;++i)o=x[i]>>d&1,sum+=t[t[p[i]].chi[o]].sum-t[t[q[i]].chi[o]].sum;
	if(k<=sum){
		for(i=l;i<=r;++i)o=x[i]>>d&1,p[i]=t[p[i]].chi[o^0],q[i]=t[q[i]].chi[o^0];
		return Query(k,l,r,L,mid,d-1);
	}
	else{
		for(i=l;i<=r;++i)o=x[i]>>d&1,p[i]=t[p[i]].chi[o^1],q[i]=t[q[i]].chi[o^1];
		return Query(k-sum,l,r,mid+1,R,d-1);
	}
}
signed main(){
	register int i,j,k,L,R,ql,qr;
	scanf("%d%d",&n,&m);
	for(i=1;i<=n;++i)scanf("%d",x+i);
	for(i=1;i<=m;++i)scanf("%d",&k),root[i]=Modify(root[i-1],k);
	scanf("%d",&Q);
	for(i=1;i<=Q;++i){
		scanf("%d%d%d%d%d",&L,&R,&ql,&qr,&k);
		for(j=L;j<=R;++j)q[j]=root[ql-1],p[j]=root[qr];
		printf("%d\n",Query((R-L+1)*(qr-ql+1)-k+1,L,R));
	}
}
posted @ 2022-01-10 16:32  Prean  阅读(24)  评论(0编辑  收藏  举报
var canShowAdsense=function(){return !!0};