UOJ #495. 晒被子

【题目描述】:

在平面直角坐标系上晒了许多块被子,被子呈矩形,边均与x或y轴平行,在(0,0)处有一个水源,水不断从(0,0)处溢出,在第t秒形成了一个以(0,0)(0,t)(t,0)(t,t)为顶点的正方形水域,在其中的被子都会被弄湿,询问某些时刻被弄湿的被子的总面积(同一格子的不同被子算多次)。

【输入描述】:

第一行2个整数n、q,表示被子总数和询问次数。

接下来n行每行4个整数x1、y1、x2、y2,表示一条被子的位置是以(x1,y1)(x2,y2)为左下角和右上角顶点的矩形。

接下来q行每行1个整数t,表示询问第t秒被子弄湿的总面积。

【输出描述】:

共q行表示每次询问的答案。

【样例输入】:

3 3
0 0 3 3
1 0 3 2
0 1 2 3
1
2
3

【样例输出】:

1
8
17

【样例说明】:

样例输入说明,下载图片

【时间限制、数据范围及描述】:

时间:1s 空间:256M

30%的数据0<=t,x1,y1,x2,y2<=1000。

50%的数据n<=1000,q<=1000。

另有20%的数据q=1。

100%的数据n<=50000,q<=100000,0<=t,x1,y1,x2,y2<=5×10^6,x1<x2,y1<y2。

下载

代码:

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;

const int N=500010;

bool p[N];
int a[N],b[N],c[N],d[N];
int n,m,t,l,x,x1,x2,y1,y2;
long long t1,t2,tot,s,ss,s2,ans[N];

void add(int x,int y,int z) {
	if(x>y)
		swap(x,y);
	s+=z;
	l++;
	a[l]=x;
	b[l]=(l+1)/2;
	c[l]=z;
	l++;
	a[l]=y;
	b[l]=l/2;
	c[l]=z;
}

void kp(int l,int r) {
	int i=l,j=r,m=a[(i+j)/2];
	while(i<=j) {
		while(a[i]<m)
			i++;
		while(a[j]>m)
			j--;
		if(i<=j) {
			swap(a[i],a[j]);
			swap(b[i],b[j]);
			swap(c[i],c[j]);
			i++;
			j--;
		}
	}
	if(i<r)
		kp(i,r);
	if(l<j)
		kp(l,j);
}

int main () {
	//freopen("sbz.in","r",stdin);
	//freopen("sbz.out","w",stdout);
	scanf("%d%d",&n,&m);
	s=0;
	for(int i=1; i<=n; i++) {
		scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
		if(x2>0&&y2>0)
			add(x2,y2,1);
		if(x1>0&&y2>0)
			add(x1,y2,-1);
		if(x2>0&&y1>0)
			add(x2,y1,-1);
		if(x1>0&&y1>0)
			add(x1,y1,1);
	}
	for(int i=1; i<=m; i++) {
		scanf("%d",&x);
		l++;
		a[l]=x;
		b[l]=i;
		c[l]=0;
	}
	kp(1,l);
	tot=0;
	s2=0;
	a[0]=0;
	for(int i=1; i<=l; i++) {
		t1=a[i-1];
		t2=a[i];
		ss=t2*t2-t1*t1;
		tot+=ss*s;
		ss=(t2-t1)*s2;
		tot+=ss;
		if(c[i]==0)
			ans[b[i]]=tot;
		else if(!p[b[i]]) {
			s2+=a[i]*c[i];
			s-=c[i];
			p[b[i]]=true;
			d[b[i]]=a[i];
		} else
			s2-=d[b[i]]*c[i];
	}
	for(int i=1; i<=m; i++)
		printf("%lld\n",ans[i]);
	return 0;
}

 

 

转载于:https://www.cnblogs.com/mysh/p/11343347.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值