HDU 4533 威威猫系列故事——晒被子
2013-03-30 10:49
218 查看
威威猫系列故事——晒被子
Time Limit: 3000/1000 MS (Java/Others) Memory Limit: 65535/32768 K (Java/Others)Total Submission(s): 230 Accepted Submission(s): 45
Problem Description
因为马拉松初赛中吃鸡腿的题目让不少人抱憾而归,威威猫一直觉得愧对大家,这几天他悄悄搬到直角坐标系里去住了。
生活还要继续,太阳也照常升起,今天,威威猫在第一象限晒了N条矩形的被子,被子的每条边都和坐标轴平行,不同被子的某些部分可能会叠在一起。这时候,在原点处突然发了场洪水,时间t的时候,洪水会蔓延到( t, t ),即左下角为( 0, 0 ) ,右上角为( t, t )的矩形内都有水。
悲剧的威威猫想知道,在时间t1, t2, t3 ... tx 的时候,他有多少面积的被子是湿的?
Input
输入数据首先包含一个正整数T,表示有T组测试数据;
每组数据的第一行首先是一个整数N,表示有N条被子;
接下来N行,每行包含四个整数x1, y1, x2, y2,代表一条被子的左下角和右上角的坐标;
然后接下来一行输入一个整数x,表示有x次询问;
再接下来x行,输入x个严格单调递增的整数,每行一个,表示威威猫想知道的时间ti。
[Technical Specification]
T <= 5
0 < N <= 20000
1 <= x1 < x2 <= 200000
1 <= y1 < y2 <= 200000
1 <= x <= 20000
1 <= ti <= 200000 (1 <= i <= x )
Output
对于每次询问,请计算并输出ti时有多少面积的被子是湿的,每个输出占一行。
Sample Input
1 2 1 1 3 3 2 2 4 4 5 1 2 3 4 5
Sample Output
0 1 5 8 8
Source
2013腾讯编程马拉松复赛第一场(3月29日)
Recommend
liuyiding
题目大意:
在第一象限中给出若干矩形(点范围1e5,矩形个数20000),现在给出一些询问(次数20000),每次询问给出一个整数t,问在(0,0)到(t,t)范围的矩形面积和。解题思路:
考虑每次询问t,对于单一矩形的面积的计算方法~对于询问t。计算如图矩形所被包含的面积可以用矩形面积S[TCFI]-S[TJGI],而S[TCFI]=(t-Fx)*(t-Fy);S[TJGI]=(t-Gx)*(t-Gy)
换句话说就是用[T和矩形左下角的点形成的面积]减去[T和矩形右下角形成的矩形面积]就是这个矩形被包含的面积!
下面来看一个类似的情况:
对于这次询问t。当前矩形被包涵的面积是S[TLFI]-S[TLEK]。即[T和矩形左下角点形成的面积]减去[T和矩形左上角点形成的矩形的面积]!
那么对于矩形被包含进(t,t)范围是什么情况呢?
这时候的面积是EHGF的面积,但我们还想计算这个面积时和T有关。仿照前面的讨论,发现S[EHGF]不就是S[TLFI]-S[TLEN]-S[TMGI]+S[TMHN]么?
换句话描述,就是[T和矩形左下角点形成的矩形面积]减去[T和矩形左上角点形成的矩形面积]减去[T和矩形右下角点形成的矩形面积]加上[T和矩形右上角点形成的矩形面积]
那么我们得到了如下算法:
输入询问t
sum=0
遍历所有矩形的四个顶点
如果该顶点在(0,0)-(t,t)的范围内
如果当前顶点是它所在矩形的左上角或右下角的点那么sum+=[(t,t)和该点形成的矩形的面积]
否则sum-=[(t,t)和该点形成的矩形的面积]
返回sum
对于这题目的数据来说时间复杂度肯定是不够的,我们要想办法优化它。。。
观察我们计算[T和当前点形成的矩形面积]时的方法:
假设当前点坐标是(x,y)
那么S=(t-x)*(t-y)
我们可以将上式展开:S=t*t-t(x+y)+xy
我们可不可以将上式分成的三部分分别求和呢?答案是可以的!
那么我们可以将所有矩形左下角和右上角的点分到一组a(因为它们和T形成的矩形面积都是做“加”运算),把左上角和右下角的点分到一组b(因为它们和T形成的矩形面积都是做“减”运算)
那么结果可以写成sigma[a中在(t,t)范围内的点和T形成的矩形面积]-sigma[b在(t,t)范围内的点和T形成的矩形面积]
很容易想到,我们将a,b中的点分别按max(x,y)排序。然后正确的算法已经呼之欲出了!
对于每次询问t,我们二分找到它在a,b中的位置n,m(即max(x,y)恰好不超过t的最大的下标,a,b都是从1开始编号)
答案不就是
Sum(Sa)-Sum(Sb)
=sigma[t*t-t*(x+y)+xy](a中点)-sigma[t*t-t*(x+y)+xy](b中点)
=[sigma(t*t)-sigma(x+y)+sigma(xy)](a中点)-[sigma(t*t)-sigma(x+y)+sigma(xy)](b中点)
计算sigma(t*t)只要t*t乘个数(对于a是n,对于b是m)即可!
计算sigma(x+y)和sigma(xy)只要预处理一下即可!
现在算法如下:
检查所有矩形的四个顶点
如果是左下角或是右上角的点那么放到a的末尾
否则放到b的末尾
将a,b中的所有点按max(x,y)排序
定义suma,sumb表示a、b的点中下标1到下标i的所有点的x+y和
定义suma_mul,sumb_mul表示a、b的点中下标1到下标i的所有点的x*y和
循环 i=1 到 2*N
suma[i]=suma[i-1]+a[i].x+a[i].y
sumb[i]=sumb[i-1]+b[i].x+b[i].y
suma_mul[i]=suma_mul[i-1]+a[i].x*a[i].y
sumb_mul[i]=sumb_mul[i-1]+b[i].y*b[i].y
对于每次询问t
二分找到在a,b中max(x,y)恰好不超过t的下标n,m
输出答案(t*t*n-t*suma
+suma_mum
)-(t*t*m-t*sumb[m]+sumb_mul[m])
另外:由于本题的询问范围是固定且是递增的,所以可以考虑在这里再次优化时间复杂度
代码:
#include<cstdio> #include<algorithm> #include<cstring> #include<iostream> using namespace std; struct point{ long long x,y; friend bool operator < (const point &a,const point &b){ return max(a.x,a.y)<max(b.x,b.y); } }; point a[50001]; long long suma[50001],sumb[50001],suma_mul[50001],sumb_mul[50001]; point b[50001]; int find_a(int l,int r,long long t){ while(r>=l){ int m=(l+r)/2; if(t==max(a[m].x,a[m].y))return m; if(t<max(a[m].x,a[m].y))r=m-1; else l=m+1; } return l; } int find_b(int l,int r,long long t){ while(r>=l){ int m=(l+r)/2; if(t==max(b[m].x,b[m].y))return m; if(t<max(b[m].x,b[m].y))r=m-1; else l=m+1; } return l; } int main(){ int T; scanf("%d",&T); while(T--){ memset(suma,0,sizeof(suma)); memset(sumb,0,sizeof(sumb)); memset(suma_mul,0,sizeof(suma_mul)); memset(sumb_mul,0,sizeof(sumb_mul)); memset(a,0,sizeof(a)); memset(b,0,sizeof(b)); int n; scanf("%d",&n); for(int i=1;i<=n;i++){ long long x1,y1,x2,y2; scanf("%I64d%I64d%I64d%I64d",&x1,&y1,&x2,&y2); //cin>>x1>>y1>>x2>>y2; a[2*i-1]=(point){x1,y1}; a[2*i]=(point){x2,y2}; b[2*i-1]=(point){x1,y2}; b[2*i]=(point){x2,y1}; } sort(a,a+2*n+1); sort(b,b+2*n+1); for(int i=1;i<=2*n;i++){ suma[i]=suma[i-1]+a[i].x+a[i].y; sumb[i]=sumb[i-1]+b[i].x+b[i].y; suma_mul[i]=suma_mul[i-1]+a[i].x*a[i].y; sumb_mul[i]=sumb_mul[i-1]+b[i].x*b[i].y; } suma[2*n+1]=suma[2*n]; sumb[2*n+1]=sumb[2*n]; suma_mul[2*n+1]=suma_mul[2*n]; sumb_mul[2*n+1]=sumb_mul[2*n]; int q; scanf("%d",&q); while(q--){ long long x; scanf("%I64d",&x); long long sum=0; int m=find_a(1,2*n,x); if(m>2*n)m=2*n; if(x<max(a[m].x,a[m].y))m--; sum=m*x*x-x*suma[m]+suma_mul[m]; m=find_b(1,2*n,x); if(m>2*n)m=2*n; if(x<max(b[m].x,b[m].y))m--; sum=sum-(m*x*x-x*sumb[m]+sumb_mul[m]); printf("%I64d\n",sum); //cout<<sum<<endl; } } }
相关文章推荐
- HDU 4533 威威猫系列故事——晒被子
- HDU-4533 威威猫系列故事——晒被子 数学分析
- hdu 4533 威威猫系列故事——晒被子
- hdu-4533-威威猫系列故事――晒被子----
- hdu 4533 威威猫系列故事——晒被子(两种方法)
- HDU 4533 威威猫系列故事――晒被子(线段树区间更新+分情况推公式)
- hdu 4533 威威猫系列故事——晒被子
- hdu 4533 威威猫系列故事——晒被子(线段树 成端更新)
- hdu 4533 威威猫系列故事——晒被子(成段更新)
- HDU 4533 威威猫系列故事——晒被子
- Hdu 4533 威威猫系列故事——晒被子
- HDU-4533:威威猫系列故事——晒被子(线段树延迟更新+推公式)
- HDU-4533 威威猫系列故事——晒被子(区间更新)
- hdu 4533 威威猫系列故事――晒被子(二重等差数列+差分前缀和)
- HDU 4533 威威猫系列故事――晒被子 (线段树)
- HDOJ 4533 威威猫系列故事——晒被子
- HDU 4540(威威猫系列故事——打地鼠)动态规划
- hdu——4540威威猫系列故事——打地鼠
- hdu-4526-威威猫系列故事——拼车记-DP
- 【腾讯第二届校园编程马拉松】HDU-4525,威威猫系列故事——吃鸡腿