[BZOJ 2735]世博会 主席树 切比雪夫距离转曼哈顿距离

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[BZOJ 2735]世博会 主席树 切比雪夫距离转曼哈顿距离相关的知识,希望对你有一定的参考价值。

知识点:切比雪夫距离转曼哈顿距离

以(x1,y1)和(x2,y2)二点为例

其切比雪夫距离为

    技术分享图片

其曼哈顿距离为

技术分享图片

题目中的距离是切比雪夫距离,而切比雪夫距离与曼哈顿距离可以互相转化

考虑二维笛卡尔坐标系的坐标原点O(0,0),与它的切比雪夫距离为1的点的集合形成的图形是一个边长为2的正方形,与它的曼哈顿距离为1的点的集合形成的图形是一个边长为1的正方形

如果把这个边长为2的正方形旋转45度再缩小2倍,两个图形即可重合

于是我们把(x,y)变换成技术分享图片,这样,切比雪夫距离就变成了曼哈顿距离了

这就意味着,在新坐标下求得的曼哈顿距离答案等于原坐标下求得的切比雪夫距离的答案

为了避免浮点数,我们把点的坐标再乘2,最后答案再除以2

我们为什么要这么做呢?因为最开始求贡献是要考虑x,y两个元素的,而曼哈顿距离为|x1−x2|+|y1−y2|,所以转化之后可以对x,y单独考虑

这道题还有一个结论:有一堆数,让你求出一个数与这堆数的差值的绝对值之和最小,那么这个数是这堆数的中位数(如果是偶数个数那么就是在中间两个数之间的任意一值)

我们可以把这堆数看成柱形图,然后在中位数处横着画一条线,可以把线提高一些或者降低,可知不会更优(自己画画图就知道了)

好啦!那么我们就离散一下,主席树内搞一下,注意树内要维护数的个数和值的总和,方便求答案

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<vector>
#include<algorithm>
#define N 101000
#define pos(i,a,b) for(int i=(a);i<=(b);i++)
using namespace std;
#define LL long long
int n,q;
LL a[N],b[N];
vector<LL> v;
int findx(int x){
	return lower_bound(v.begin(),v.end(),x)-v.begin()+1;
}
struct haha{
	int lc,rc,num;LL sum;
}tree1[N*25],tree2[N*25];
int root1[N],root2[N];
int size1,size2,len;
void update1(int &rt,int l,int r,int pos,LL num){
	tree1[++size1]=tree1[rt];
	int t=size1;tree1[t].num++;tree1[t].sum+=num;
	rt=t;
	if(l==r) return;
	int mid=(l+r)>>1;
	if(pos<=mid) update1(tree1[rt].lc,l,mid,pos,num);
	else update1(tree1[rt].rc,mid+1,r,pos,num);
}
void update2(int &rt,int l,int r,int pos,LL num){
	tree2[++size2]=tree2[rt];
	int t=size2;tree2[t].num++;tree2[t].sum+=num;
	rt=t;
	if(l==r) return;
	int mid=(l+r)>>1;
	if(pos<=mid) update2(tree2[rt].lc,l,mid,pos,num);
	else update2(tree2[rt].rc,mid+1,r,pos,num);
}
LL tot1_l;
int query1(int rtl,int rtr,int l,int r,int k){
	if(l==r){
		tot1_l+=v[l-1];
		return l;
	} 
	int num=tree1[tree1[rtr].lc].num-tree1[tree1[rtl].lc].num;
	LL sum=tree1[tree1[rtr].lc].sum-tree1[tree1[rtl].lc].sum;
	int mid=(l+r)>>1;
	if(num>=k){
		return query1(tree1[rtl].lc,tree1[rtr].lc,l,mid,k);
	}
	else{
		tot1_l+=sum;
		return query1(tree1[rtl].rc,tree1[rtr].rc,mid+1,r,k-num);
	}
}
LL tot2_l;
int query2(int rtl,int rtr,int l,int r,int k){
	if(l==r){
		tot2_l+=v[l-1];
		return l;
	} 
	int num=tree2[tree2[rtr].lc].num-tree2[tree2[rtl].lc].num;
	LL sum=tree2[tree2[rtr].lc].sum-tree2[tree2[rtl].lc].sum;
	int mid=(l+r)>>1;
	if(num>=k){
		return query2(tree2[rtl].lc,tree2[rtr].lc,l,mid,k);
	}
	else{
		tot2_l+=sum;
		return query2(tree2[rtl].rc,tree2[rtr].rc,mid+1,r,k-num);
	}
}
int main(){
	scanf("%d%d",&n,&q);len=n*2;
	pos(i,1,n) scanf("%lld",&a[i]);
	pos(i,1,n) scanf("%lld",&b[i]);
	pos(i,1,n){
		LL x=a[i],y=b[i];
		a[i]=(x+y);b[i]=(x-y);
		v.push_back(a[i]);
		v.push_back(b[i]);
	}
	sort(v.begin(),v.end());
	v.erase(unique(v.begin(),v.end()),v.end());
	pos(i,1,n){
		root1[i]=root1[i-1];
		update1(root1[i],1,len,findx(a[i]),a[i]);
		root2[i]=root2[i-1];
		update2(root2[i],1,len,findx(b[i]),b[i]);
	}
	pos(i,1,q){
		int x,y;double ans=0.0;scanf("%d%d",&x,&y);
		LL cnt1(0),tot1(0),cnt1_l(0),mid1(0);
		cnt1=tree1[root1[y]].num-tree1[root1[x-1]].num;
		tot1=tree1[root1[y]].sum-tree1[root1[x-1]].sum;
		tot1_l=0;cnt1_l=(cnt1>>1)+1;
		mid1=v[query1(root1[x-1],root1[y],1,len,cnt1_l)-1];
		ans+=cnt1_l*mid1-tot1_l+(tot1-tot1_l)-mid1*(cnt1-cnt1_l);
		LL cnt2(0),tot2(0),cnt2_l(0),mid2(0);
		cnt2=tree2[root2[y]].num-tree2[root2[x-1]].num;
		tot2=tree2[root2[y]].sum-tree2[root2[x-1]].sum;
		tot2_l=0;cnt2_l=(cnt2>>1)+1;
		mid2=v[query2(root2[x-1],root2[y],1,len,cnt2_l)-1];
		ans+=cnt2_l*mid2-tot2_l+(tot2-tot2_l)-mid2*(cnt2-cnt2_l);
		printf("%.2f\\n",ans/2);
	}
	return 0;
}

  

以上是关于[BZOJ 2735]世博会 主席树 切比雪夫距离转曼哈顿距离的主要内容,如果未能解决你的问题,请参考以下文章

瞎题表

[省选]省选知识点进度

bzoj2989&&4170数列——二进制分组+主席树

BZOJ 3170 & 切比雪夫距离

bzoj 3170 Tjoi 2013 松鼠聚会 曼哈顿距离&&切比雪夫距离

BZOJ_3170_[Tjoi2013]松鼠聚会_切比雪夫距离+前缀和