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

2735: 世博会

Time Limit: 20 Sec  Memory Limit: 128 MB
Submit: 124  Solved: 51
[Submit][Status][Discuss]

Description

四年一度的世博会又要举办了,Q国很荣幸成为了这次世博会的主办方。Q国主席QQ从全国各地收集了N件物品排成

一排,作为Q国馆的展出物。对于相邻摆放的一些物品,如果过于相似会让人觉得无聊,如果差别过大又会让人觉

得突兀。为了让人们对这次世博会的展出满意,QQ需要知道一些相邻物品的“差异度”。为了方便表示,QQ给每个

物品都定义了两个属性值A、B,两件物品之间的“绝对差异值”定义为它们对应属性的差的绝对值较大的一个。对

于一些物品的“差异度”,类似求方差的方法,QQ总会首先设想一个理想的“平均物品”,它的两个属性可以为任

意实数,且它与这些物品中的每个物品的“绝对差异值”之和最小。而这些物品的“差异度”就定义为这个最小的

和。QQ每次会询问:从第Li个到第Ri个物品的“差异度”是多少。现在,这个任务交给了神犇你。

Input

第一行两个整数N和Q,表示物品数和QQ的询问数。第二行N个整数A1到An,表示每个物品的A属性。第三行N个整数B

1到Bn,表示每个物品的B属性。之后Q行每行两个整数Li Ri,表示QQ的询问。

1<=N<=100000, 1<=Q<=100000, |Ai|,|Bi|<=1000000000,1<=Li<=Ri<=N

Output

共Q行,每行输出一个数,表示该次询问的物品的差异度,结果保留到小数点后两位。

Sample Input

4 2
1 6 -3 2
2 7 -1 3
1 4
2 3

Sample Output

10.00
9.00
样例说明
对于第一个询问,平均物品的两个属性可以是1和2差异度为max(0,0)+max(5,5)+max(4,3)+max(1,1)=10对于第二个
询问,平均物品的两个属性可以是6和7差异度为max(0,0)+max(9,8)=9

Solution

题意:每次询问要你给出$(A_0,B_0)$,最小化$\sum_{i=L}^{R} max{|A_i-A_0|,|B_i-B_0|} $。

先来点干货:

  • 切比雪夫距离:每一维差绝对值的最大值  $max\{|x_i-x_j|,|y_i-y_j|\}$

  • 曼哈顿距离:每一维差绝对值之和 $|x_i-x_j|+|y_i-y_j|$

  • 二维切比雪夫距离转曼哈顿距离:把坐标系旋转一下,然后再拉伸下。$(x,y)->(\frac{1}{2}(x-y),\frac{1}{2}(x+y))$

想法:将(A,B)当成二维坐标。然后再转换为(A-B,A+B)。问题变成最小化$\sum_{i=L}^{R} {|A_i-A_0|+|B_i-B_0|} $。每一维是独立的,并且每一维选中位数是最优的之一。所以用主席树维护一下查第K大,前\后缀和。

Code $O(n \log n)$

#include < cstdio >
#include < algorithm >

#define gec     getchar
#define FILE(F) freopen(F".in","r",stdin),freopen(F".out","w",stdout)
#define DEBUG   fprintf(stderr,"Passing [%s] in Line (%d)\n",__FUNCTION__,__LINE__)

typedef long long ll;
template < typename T >
inline void read(T &x)
{
	x=0;bool f=0; char c=gec();
	for(;c<‘0‘||c>‘9‘;c=gec())f=(c==‘-‘);
	for(;c>=‘0‘&&c<=‘9‘;c=gec())x=x*10+c-‘0‘;
	x=f?-x:x;
}

const int MAXN(100010);
int n,q,A[MAXN],B[MAXN],X[MAXN],Y[MAXN];

struct AXLE
{
	int a[MAXN],up;
	void ins(int x){a[++up]=x;}
	void build()
	{
		std::sort(a+1,a+1+up);
		int _up=1;
		for(int i=2;i<=up;i++)if(a[i]!=a[i-1])a[++_up]=a[i];
		up=_up;
	}
	int Find(int x)
	{
		int l=1,r=up,mid,id=1;
		while(l<=r)if(a[mid=(l+r)>>1]<=x)l=mid+1,id=mid;else r=mid-1;
		return id;
	}
}axle;

namespace ChairMan_Tree
{
	const int MAX_L(2000010);
	struct CMT
	{
		int nx[MAX_L][2],Siz[MAX_L]; 	 ll Sum[MAX_L];
		int root[MAXN],stot,Val[MAXN],N;

		void update(int k)
		{Sum[k]=Sum[nx[k][0]]+Sum[nx[k][1]];
		 Siz[k]=Siz[nx[k][0]]+Siz[nx[k][1]];}

		void modfiy(int&k,int k2,int L,int R,int x)//val[x]++;
		{
			if(!k)k=++stot,Sum[k]=Sum[k2],Siz[k]=Siz[k2];
			if(L==R){Sum[k]+=Val[x];Siz[k]++; return ;}
			int MID=(L+R)>>1;
			if(x<=MID)modfiy(nx[k][0],nx[k2][0],L,MID,x),nx[k][1]=nx[k2][1];
			else 	modfiy(nx[k][1],nx[k2][1],MID+1,R,x),nx[k][0]=nx[k2][0];
			update(k);
		}

		ll Que(int k1,int k2,int Rank)//查询区间第K大以及前\后缀和
		{
			int L=1,R=N,MID,Siz_L=0,Siz_R=0;
			ll Sum_L=0,Sum_R=0;
			while(L!=R)
			{
				MID=(L+R)>>1;
//				fprintf(stderr,"%d %d %d\n",L,R,Rank);
//				fprintf(stderr,"%d\n",Siz[nx[k1][0]]-Siz[nx[k2][0]]);
				if(Siz[nx[k1][0]]-Siz[nx[k2][0]]<Rank)
				Siz_L+=Siz[nx[k1][0]]-Siz[nx[k2][0]],Sum_L+=Sum[nx[k1][0]]-Sum[nx[k2][0]],
//				fprintf(stderr,"%d %d %lld\n",L,MID,Sum[nx[k1][0]]-Sum[nx[k2][0]]),
				L=MID+1,Rank-=Siz[nx[k1][0]]-Siz[nx[k2][0]],k1=nx[k1][1],k2=nx[k2][1];
				else
				Siz_R+=Siz[nx[k1][1]]-Siz[nx[k2][1]],Sum_R+=Sum[nx[k1][1]]-Sum[nx[k2][1]],
				R=MID,k1=nx[k1][0],k2=nx[k2][0];
			}
//			fprintf(stderr,"%lld %d %lld %d %d %d\n",Sum_L,Siz_L,Sum_R,Siz_R,L,Val[L]);
			return (ll)Siz_L*Val[L]-Sum_L+Sum_R-(ll)Siz_R*Val[L];
		}

	}A_Tree,B_Tree;

}using namespace ChairMan_Tree;

void Pretreat()
{
	for(int i=1;i<=n;i++)axle.ins(A[i]); axle.build();
	for(int i=1;i<=n;i++)A[i]=axle.Find(A[i]);
	A_Tree.N=axle.up; for(int i=1;i<=A_Tree.N;i++)A_Tree.Val[i]=axle.a[i];
	for(int i=1;i<=n;i++)A_Tree.modfiy(A_Tree.root[i],A_Tree.root[i-1],1,A_Tree.N,A[i]);
	axle.up=0;
	for(int i=1;i<=n;i++)axle.ins(B[i]); axle.build();
	for(int i=1;i<=n;i++)B[i]=axle.Find(B[i]);
	B_Tree.N=axle.up; for(int i=1;i<=B_Tree.N;i++)B_Tree.Val[i]=axle.a[i];
	for(int i=1;i<=n;i++)B_Tree.modfiy(B_Tree.root[i],B_Tree.root[i-1],1,B_Tree.N,B[i]);
}

int main()
{
#ifndef ONLINE_JUDGE
	FILE("C");
#endif
	read(n);read(q);
	for(int i=1;i<=n;i++)read(X[i]);
	for(int i=1;i<=n;i++)read(Y[i]);
	for(int i=1;i<=n;i++)A[i]=X[i]-Y[i],B[i]=X[i]+Y[i];
	Pretreat();
	for(int i=1,L,R;i<=q;i++)
	{
		read(L);read(R);
		ll Ans_A=A_Tree.Que(A_Tree.root[R],A_Tree.root[L-1],(R-L+2)>>1);
		ll Ans_B=B_Tree.Que(B_Tree.root[R],B_Tree.root[L-1],(R-L+2)>>1);
		printf("%.2lf\n",(Ans_A+Ans_B)*0.5);
	}
	return 0;
}
时间: 2024-08-02 15:14:25

BZOJ 2735: 世博会 主席树+切比雪夫距离转曼哈顿距离的相关文章

各种距离 欧式距离、曼哈顿距离、切比雪夫距离、闵可夫斯基距离、标准欧氏距离、马氏距离、余弦距离、汉明距离、杰拉德距离、相关距离、信息熵

1. 欧氏距离(Euclidean Distance) 欧氏距离是最容易直观理解的距离度量方法,我们小学.初中和高中接触到的两个点在空间中的距离一般都是指欧氏距离. 二维平面上点a(x1,y1)与b(x2,y2)间的欧氏距离: 三维空间点a(x1,y1,z1)与b(x2,y2,z2)间的欧氏距离: n维空间点a(x11,x12,…,x1n)与b(x21,x22,…,x2n)间的欧氏距离(两个n维向量): Matlab计算欧氏距离: Matlab计算距离使用pdist函数.若X是一个m×n的矩阵,

bzoj 2653 middle (主席树+二分)

版权声明:本文为博主原创文章,未经博主允许不得转载. bzoj 2653 题意: 一个长度为n的序列a,设其排过序之后为b,其中位数定义为b[n/2],其中a,b从0开始标号,除法取下整. 给你一个长度为n的序列s. 回答Q个这样的询问:s的左端点在[a,b]之间,右端点在[c,d]之间的子序列中,最大的中位数. 其中a<b<c<d. 位置也从0开始标号. 强制在线. 解法: 首先可以想到的是二分答案,再判断是否满足条件 . 对于答案x,我们将原数组中大于等于x的数记1,小于的记为-1,

BZOJ 1516 [POI2006]Mag-Warehouse 切比雪夫距离转曼哈顿距离

题意: 给定一个网格图,其上有一堆坏点(整点,同一位置多个),求一个整点,使得该整点到所有的坏点的切比雪夫距离之和最小. 求这个整点位置. 无SPJ 解析: 看完题懵了,我只会曼哈顿距离啊怎么办. 然后就无聊查了下给定的那个计算公式,哇塞这居然叫切比雪夫距离. 噫怎么有个链接是谈切比雪夫转化曼哈顿距离的. 噫看完后我就会这道题辣! 对于原坐标系中两点间的 Chebyshev 距离,是将坐标轴顺(逆)时针旋转45度并将所有点的坐标值放大sqrt(2)倍所得到的新坐标系中的Manhattan距离的二

bzoj 3653 谈笑风生——主席树

题目:https://www.lydsy.com/JudgeOnline/problem.php?id=3653 原来一直想怎么线段树合并.可是不会把角标挪一位. 查询的其实是子树内一段深度的点的 siz 和.因为是子树内,所以按 dfs 序建立主席树,角标是 dep ,值是 siz . 注意 long long .而且数组 *19 就会 RE ,*20就好了.不知为何. #include<iostream> #include<cstdio> #include<cstring

BZOJ 2653: middle [主席树 中位数]

传送门 题意: 一个长度为n的序列a,设其排过序之后为b,其中位数定义为b[n/2],其中a,b从0开始标号,除法取下整.给你一个 长度为n的序列s.回答Q个这样的询问:s的左端点在[a,b]之间,右端点在[c,d]之间的子序列中,最大的中位数. 我会使用一些方式强制你在线. 最后一句话太可怕了$QAQ$ 首先需要知道怎么求中位数: 二分答案,$\ge$的为$1$,$<$的为$-1$,如果和$\ge 0$说明当前答案$\le$中位数 最大中位数?$GSS$! 只要求$[a,b].rm+(b,c)

BZOJ 3514 LCT+主席树

思路: //By SiriusRen #include <bits/stdc++.h> using namespace std; const int N=400500; int n,m,k,type,ch[N][2],fa[N],minn[N],rev[N],q[N],top,pre[N]; int root[N],tree[N*50],lson[N*50],rson[N*50],cnt,xx,yy,ans; struct Road{int x,y,wei;}road[N]; bool isr

BZOJ 2653 middle | 主席树

题目: http://www.lydsy.com/JudgeOnline/problem.php?id=2653 题解: 设答案为ans,把大于等于ans的记为1,小于的记为-1,这样可以知道当前ans是大了还是小了 然后二分答案,就是求最大子段和的问题,根据网上的题解:[b,c]是必选的,然后选[a,b]和[c,d]的最大字段和就行了 #include<cstdio> #include<cstring> #include<algorithm> #define N 20

HDU 4312 最小切比雪夫距离-转化成曼哈顿距离再分治

题意:二维空间,n个点,求以某点为起点到各点的最小切比雪夫距离 分析: 上一道题之前已经用"分治"思想在O(n)的时间内求出了n个点,以某点为起点到各点的最小曼哈顿距离,那么我们根据二维空间切比雪夫距离和曼哈顿距离的关系,可以把切比雪夫距离转化成曼哈顿距离,再直接用之前的方法即可. 二维空间: 曼哈顿距离 :d=|x1-x2|+|y1-y2|,到某点的曼哈顿距离为r的点组成一个边长为√2*r的正方形,且边与坐标轴成45度 切比雪夫距离:d=max(|x1-x2|,|y1-y2|),到某

POJ 3241 Object Clustering 二维平面曼哈顿距离最小生成树

题目链接:点击打开链接 题意: 给定二维平面上的n个点坐标,常数k 下面n行给出坐标 求一个最小生成树,问第k大的边是多少. 任意两个点间建一条边的花费是其曼哈顿距离. 思路:转自:点击打开链接 一.曼哈顿距离最小生成树 曼哈顿距离最小生成树问题可以简述如下: 给定二维平面上的N个点,在两点之间连边的代价为其曼哈顿距离,求使所有点连通的最小代价. 朴素的算法可以用O(N2)的Prim,或者处理出所有边做Kruskal,但在这里总边数有O(N2)条,所以Kruskal的复杂度变成了O(N2logN