方法一:
把(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,y2),Min(x2,y2))~Max(x2,y2)这两个区间
如果Max(x1,y2)<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,y2),Min(x2,y2))~Max(x2,y2)这个区间,画个图就明白了;
对于Max(MAx(x1,y2),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;
}
题目大意:
在第一象限中给出若干矩形(点范围1e5,矩形个数20000),现在给出一些询问(次数20000),每次询问给出一个整数t,问在(0,0)到(t,t)范围的矩形面积和。
解题思路:
![](https://img-my.csdn.net/uploads/201303/30/1364612560_9016.png)
![](https://i-blog.csdnimg.cn/blog_migrate/476d65578736db9a89dc962b8608f151.png)
![](https://img-my.csdn.net/uploads/201303/30/1364612638_7284.png)
![](https://i-blog.csdnimg.cn/blog_migrate/476d65578736db9a89dc962b8608f151.png)
![](https://img-my.csdn.net/uploads/201303/30/1364612712_9910.png)
![](https://i-blog.csdnimg.cn/blog_migrate/476d65578736db9a89dc962b8608f151.png)
#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;
}
}
}