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

/*

把(0,0),(t,t)看成是一个大矩形的话,那么这个大矩形的右上坐标x是等于y的,有了这个就好办了,

我们可以维持一颗关于t的线段树,比如现在对一个X矩形(x1,y1),(x2,y2)来说如果t>=Max(x2,y2),那么这个面积直接加上;

在关于t的这颗线段树上操作也就是相当于更新(Max(x2,y2)~Max(t))这个区间,而对于(0~MAx(x1,y1))这个区间是无影响的;


现在在于怎么处理MAx(x1,y1)~Min(x2,y2)和Max(MAx(x1,y1),Min(x2,y2))~Max(x2,y2)这两个区间

如果Max(x1,y1)<Min(x2,y2),那么这端区间和X矩形的相交的面积就是(t-x1)*(t-y1);而这里t是变动的,

所以我把式子变一下得t*t-(x1+y1)*t+x1*y1,这样我们可以开三个数组保存这个方程的系数(1,-(x1+y1),x1*y1),

因为这三个系数是常数并且可以进行加减运算,然后一样可以利用线段树的lazy思想,系数到最后再计算是一样的。


用类似的方法去处理Max(MAx(x1,y1),Min(x2,y2))~Max(x2,y2)这个区间,画个图就明白了;


对于Max(MAx(x1,y1),Min(x2,y2))~Max(x2,y2)这个区间处理有两种情况(如下图,手画的,只能看个大概):

这是第一种情况(y2>x2):



 

重叠面积为(t-x1)*(t-y1)-(t-x2)*(t-y1)展开为:(-x1-y1+y1+x2)*t+y1*(x1-x2);和前面一样在线段树区间上更新这个方程的系数

第二种情况(x2>y2):



 

重叠面积为(t-x1)*(t-y1)-(t-x1)*(t-y2)展开为:(-x1-y1+x1+y2)*t+x1*(y1-y2);和前面一样在线段树区间上更新这个方程的系数


上面的介绍体现在POP函数里面,主要的思想是利用保存系数达到目的;

今天比赛太挫了,A题弄了我好久wa了好几次,D题也没在比赛的时候过,太悲剧了大哭

*/


#include<stdio.h>
#include<string.h>

#define _LL __int64

int n=200000;
_LL A[800000],B[800000],C[800000];

void update(int i,int l,int r,int a,int b,_LL *v)
{
	int mid;
	if(a>b) return;
	if(a==l&&r==b)
	{
		A[i]+=v[0];B[i]+=v[1];C[i]+=v[2];
		return ;
	}
	mid=(l+r)/2;
	if(b<=mid) update(i<<1,l,mid,a,b,v);
	else if(a>mid) update(i<<1|1,mid+1,r,a,b,v);
	else {
		update(i<<1,l,mid,a,mid,v);
		update(i<<1|1,mid+1,r,mid+1,b,v);
	}
}

_LL query(int i,int l,int r,_LL p)
{
	int mid;
	if(l==r) return p*p*A[i]+p*B[i]+C[i];
	mid=(l+r)/2;
	A[i<<1]+=A[i];B[i<<1]+=B[i];C[i<<1]+=C[i];
	A[i<<1|1]+=A[i];B[i<<1|1]+=B[i];C[i<<1|1]+=C[i];
	A[i]=B[i]=C[i]=0;
	if(p<=mid) return query(i<<1,l,mid,p);
	else return query(i<<1|1,mid+1,r,p);
} 


void POP(_LL a,_LL b,_LL x,_LL y)
{
	int m=a<b?b:a,t=x>y?x:y,t2=x>y?y:x;
	_LL v[3]={0,0,0};
	v[2]=(x-a)*(y-b);
	update(1,1,n,t+1,n,v);
	v[0]=1;v[1]=-(a+b);v[2]=a*b;
	if(t2>=m) update(1,1,n,m+1,t2,v);
	if(y>x){
		v[0]-=1;
		v[1]+=x+b;v[2]-=x*b;
	}
	else if(x>y)
	{
		v[0]-=1;
		v[1]+=a+y;v[2]-=a*y;
	}
	if(m>t2) t2=m;
	update(1,1,n,t2+1,t,v);
}

int main()
{
	int cas,m,i;
	_LL x1,x2,y1,y2;
	scanf("%d",&cas);
	while(cas--)
	{
		memset(A,0,sizeof(A));
		memset(B,0,sizeof(B));
		memset(C,0,sizeof(C));
		scanf("%d",&m);
		for(i=1;i<=m;i++)
		{
			scanf("%I64d%I64d%I64d%I64d",&x1,&y1,&x2,&y2);
			POP(x1,y1,x2,y2);
		}
		scanf("%d",&m);
		while(m--)
		{
			scanf("%I64d",&x1); 
			printf("%I64d\n",query(1,1,n,x1));
		}
	}
	return 0;
}



评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值