1. 程式人生 > >[BZOJ 2735]世博會 主席樹 切比雪夫距離轉曼哈頓距離

[BZOJ 2735]世博會 主席樹 切比雪夫距離轉曼哈頓距離

find 一個數 blog 卡爾 題目中的 i++ 坐標系 畫畫 笛卡爾

知識點:切比雪夫距離轉曼哈頓距離

以(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]世博會 主席樹 切比雪夫距離轉曼哈頓距離