Hdu 4533 威威猫系列故事——晒被子

威威猫系列故事——晒被子

Time Limit: 3000/1000 MS (Java/Others)    Memory Limit: 65535/32768 K (Java/Others)
Total Submission(s): 949    Accepted Submission(s): 235


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
 
思路:   滚动数组 
分3部分加区间和。 A * t * t + B * t + C = answer  
  
第一部分是

对任意一个矩形,在更新t1 ~ t2的区间: 即斜线阴影部分    面积的等于 (t - x1) * (t - y1)  化简得 t * t - (x1 + y1) t + x1*y1; 即 A = 1 , B = - ( x1 + y1)  C = x1 * y1;

在更新t2 ~ t3 的区间  即竖线蓝色的阴影部分。  面积等于 (t - x1) * (t - y1) - (t - x2) * (t - y1) 化简得  (-(x1 + y1) + x2 + y1) * t + x1 * y1 - x2 * y1  即  A = 0,  B= -(x1 + y1) + x2 + y1;
C = x1 * y1 - x2 * y1;

在更新区间 t3 ~ 200000时  即全部面积。   (y2 - y1) * (x2 - x1)  即  A = 0, B = 0,  C = (y2 - y1) * (x2 - x1);

#include <cstdio>
#include <cstring>
const int v = 200005;
int T, N, x;
__int64 a, b, c, A[v], B[v], C[v];
void f(int s, int t) {
	A[s] += a;
	B[s] += b;
	C[s] += c;
	A[t + 1] += -a;
	B[t + 1] += -b;
	C[t + 1] += -c;
}
void insert(__int64 x1, __int64 y1, __int64	x2, __int64 y2) {
	int m = x1 > y1 ? x1 : y1, t = x2 > y2 ? x2 : y2, t2 = x2 > y2 ? y2 : x2;
	a = b = c = 0;
	c = (x2 - x1) * (y2 - y1);
	f(t + 1, v - 5);
	a = 1;
	b = -(x1 + y1);
	c = x1 * y1;
	if(t2 >= m)
		f(m + 1, t2);
	else
		t2 = m;
	if(y2 > x2) {
		a -= 1;
		b +=  x2 + y1;
		c -=  x2 * y1;
	}
	else if(x2 > y2) {
		a -= 1;
		b +=  x1 + y2;
		c -=  x1 * y2;
	}
	f(t2 + 1, t);
}
int main() {
	scanf("%d", &T);
	while(T--) {
		memset(A, 0, sizeof(A));
		memset(B, 0, sizeof(B));
		memset(C, 0, sizeof(C));
		scanf("%d", &N);
		for(int i = 0; i < N; ++i) {
			__int64 x1, y1, x2, y2;
			scanf("%I64d%I64d%I64d%I64d", &x1, &y1, &x2, &y2);
			insert(x1, y1, x2, y2);
		}
		for(int i = 1; i < v; ++i) {
			A[i] += A[i-1];
			B[i] += B[i-1];
			C[i] += C[i-1];
		}
		scanf("%d", &x);
		while(x--) {
			__int64 t;
			scanf("%I64d", &t);
			printf("%I64d\n", t * t * A[t] + t * B[t] + C[t]);
		}
	}	
}

附线段树版  没有滚动数组给力。  连个版本主要看 insert()函数。 

#include <cstdio>
const int v = 600000;
const int size = 200000;
typedef struct node{
	__int64 a, b, c;
	int l, r;
}node;
node nod[v];
int T, N;
__int64 a, b, c;
void build(int root, int st, int ed) {
	nod[root].l = st;
	nod[root].r = ed;
	nod[root]. a = nod[root].b = nod[root].c = 0;
	if(ed != st) {
		int mid = (st + ed) / 2;
		build(root * 2, st, mid);
		build(root * 2 + 1, mid + 1, ed);
	}
}
void updata(int root, int l, int r) {
	if(l > r)
		return ;
	if(nod[root].l == l && nod[root].r == r) {
		nod[root].a += a;
		nod[root].b += b;
		nod[root].c += c;
		return ;
	}
	int mid = (nod[root].l + nod[root].r) / 2;
	if(r <= mid)
		updata(root * 2, l, r);
	else if(l > mid)
		updata(root * 2 + 1, l, r);
	else {
		updata(root * 2, l, mid);
		updata(root * 2 + 1, mid + 1, r);
	}
}
__int64 Qurry(int root, __int64 t) {
	if(nod[root].l == nod[root].r)
			return t * t * nod[root].a + t * nod[root].b + nod[root].c;
	nod[root * 2].a += nod[root].a;
	nod[root * 2].b += nod[root].b;
	nod[root * 2].c += nod[root].c;
	nod[root * 2 + 1].a += nod[root].a;
	nod[root * 2 + 1].b += nod[root].b;
	nod[root * 2 + 1].c += nod[root].c;
	nod[root].a = nod[root].b = nod[root].c = 0;
	int mid = (nod[root].l + nod[root].r) / 2;
	if(t <= mid)
		return Qurry(2 * root, t);
	else
		return Qurry(2 * root + 1, t);
}
void insert(__int64 x1, __int64 y1, __int64 x2, __int64 y2) {
	int m = x1 > y1 ? x1 : y1, t = x2 > y2 ? x2 : y2, t2 = x2 > y2 ? y2 : x2;
	a = b = c = 0;
	c = (x2 - x1) * (y2 - y1);
	updata(1, t + 1, size);
	a = 1;
	b = -(x1 + y1);
	c = x1 * y1;
	if(t2 >= m)
		updata(1, m + 1, t2);
	else
		t2 = m;
	if(y2 > x2) {
		a -= 1;
		b += x2 + y1;
		c -= x2 * y1;
	}
	else if(x2 > y2) {
		a -= 1;
		b += x1 + y2;
		c -= x1 * y2;
	}
	updata(1, t2 + 1, t);
}
int main() {
	int i, j, k, x;
	__int64 x1, x2, y1, y2, t;
	scanf("%d", &T);
	while(T--) {
		build(1, 1, size);
		scanf("%d", &N);
		for(i = 0; i < N; ++i) {
			scanf("%I64d%I64d%I64d%I64d", &x1, &y1, &x2, &y2);
			insert(x1, y1, x2, y2);
		}
		scanf("%d", &x);
		while(x--) {
			scanf("%I64d", &t);
			printf("%I64d\n", Qurry(1, t));
		}
	}	
}




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值