标签:线段树
1 2 1 1 3 3 2 2 4 4 5 1 2 3 4 5
0 1 5 8 8
这题里求的面积是各个矩形的面积和,并不是矩形面积的并,即相互不影响,因为对于各个时段,矩形的面积都可以用A*t^2+B*t+C表示,所以我们可以用树状数组或者线段树分别维护A,B,C,每次读入一个矩形,就记录它对不同时间段t的影响,然后把相应的系数加到线段树中。
当一个矩形读入时(左下角坐标(x1,y1),右上角坐标(x2,y2)),有四种影响情况:
1.0~max(x1,y1) 这个时期因为t时间形成的矩形在该矩形下面,对面积没有影响,所以不用考虑。
2.如果存在t时间形成的矩形部分覆盖该矩形,但没有碰到或者超过该矩形的上边或者右边,那么要同时更新A,B,C,表达式为(t-x1)*(t-y1)。这里的判断表达式为如果(max(x1,y1)<min(x2,y2)),则更新max(x1,y1)~min(x2,y2)。
3.t时间内形成的矩形恰好碰到或者越过右边或上边的一条,即这段时间内的矩形面积变化中(x2-x1)或(y2-y1)为常数,那么要更新,注意,这里更新的时候要分类讨论,具体看代码。
4.max(x2,y2)~maxn,这个时期因为t时间形成的矩形已经完全覆盖矩形,所以要更新C,加上面积常数。
写线段树的时候注意,三个变量要一起存,不能开三个线段树,会超内存的。
线段树代码:
#include<iostream> #include<stdio.h> #include<stdlib.h> #include<string.h> #include<math.h> #include<vector> #include<map> #include<set> #include<queue> #include<stack> #include<string> #include<algorithm> using namespace std; #define ll __int64 #define maxn 200050 ll A,B,C; ll a[10]; struct node{ ll l,r,cnt1,cnt2,cnt3,flag; }b[4*maxn]; void build(ll l,ll r,ll i) { ll mid; b[i].l=l;b[i].r=r;b[i].cnt1=b[i].cnt2=b[i].cnt3=0;b[i].flag=1; if(l==r)return; mid=(l+r)/2; build(l,mid,i*2); build(mid+1,r,i*2+1); } void update(ll l,ll r,ll a[],ll i) { ll mid; if(b[i].l==l && b[i].r==r){ b[i].cnt1+=a[1];b[i].cnt2+=a[2];b[i].cnt3+=a[3];return; } mid=(b[i].l+b[i].r)/2; if(r<=mid)update(l,r,a,i*2); else if(l>mid)update(l,r,a,i*2+1); else{ update(l,mid,a,i*2); update(mid+1,r,a,i*2+1); } } void question(ll id,ll i) { ll mid; if(b[i].l==id && b[i].r==id){ A=b[i].cnt1;B=b[i].cnt2;C=b[i].cnt3;return; } if(b[i].cnt1){ b[i*2].cnt1+=b[i].cnt1; b[i*2+1].cnt1+=b[i].cnt1; b[i].cnt1=0; } if(b[i].cnt2){ b[i*2].cnt2+=b[i].cnt2; b[i*2+1].cnt2+=b[i].cnt2; b[i].cnt2=0; } if(b[i].cnt3){ b[i*2].cnt3+=b[i].cnt3; b[i*2+1].cnt3+=b[i].cnt3; b[i].cnt3=0; } mid=(b[i].l+b[i].r)/2; if(id<=mid)question(id,i*2); else question(id,i*2+1); } int main() { ll i,j,x1,x2,y1,y2,t,t1,t2; int T,n,m; scanf("%d",&T); while(T--) { scanf("%d",&n); build(1,maxn,1); for(i=1;i<=n;i++){ scanf("%I64d%I64d%I64d%I64d",&x1,&y1,&x2,&y2); if(max(x1,y1)<min(x2,y2)){ a[1]=1;a[2]=-(x1+y1);a[3]=x1*y1; update(max(x1,y1),min(x2,y2)-1,a,1); } if(x2<y2){ a[1]=0;a[2]=-x1+x2;a[3]=y1*(x1-x2); update(max(x2,y1),y2-1,a,1); } if(y2<x2){ a[1]=0;a[2]=-y1+y2;a[3]=x1*(y1-y2); update(max(y2,x1),x2-1,a,1); } a[1]=0;a[2]=0;a[3]=(x2-x1)*(y2-y1); update(max(x2,y2),maxn,a,1); } scanf("%d",&m); for(i=1;i<=m;i++){ scanf("%I64d",&t); A=B=C=0; question(t,1); printf("%I64d\n",A*t*t+B*t+C); } } return 0; }树状数组代码://速度快了一倍= =
#include <iostream> #include <cstdio> #include <cstring> #define maxn 200010 #define ll __int64 using namespace std; ll max(ll a,ll b){ return a>b?a:b; } ll min(ll a,ll b){ return a<b?a:b; } struct segment{ ll b[maxn],ans; void clear(){ memset(b,0,sizeof(b)); } int lowbit(ll x){ return x&(-x); } void update(ll pos,ll num){ while(pos<=maxn){ b[pos]+=num;pos+=lowbit(pos); } } ll getsum(ll pos){ ans=0; while(pos>0){ ans+=b[pos];pos-=lowbit(pos); } return ans; } }A,B,C; void fun(ll l,ll r,ll num1,ll num2,ll num3){ A.update(l,num1);A.update(r+1,-num1); B.update(l,num2);B.update(r+1,-num2); C.update(l,num3);C.update(r+1,-num3); } int main() { int t; scanf("%d",&t); while(t--) { A.clear(); B.clear(); C.clear(); int n,m; scanf("%d",&n); for(int i=0;i<n;i++) { ll x1,y1,x2,y2; scanf("%I64d%I64d%I64d%I64d",&x1,&y1,&x2,&y2); if(max(x1,y1)<min(x2,y2)) fun(max(x1,y1),min(x2,y2),1,-(x1+y1),x1*y1); if(x2<y2) fun(max(x2,y1)+1,y2,0,-x1+x2,y1*(x1-x2)); if(y2<x2) fun(max(y2,x1)+1,x2,0,-y1+y2,x1*(y1-y2)); fun(max(x2,y2)+1,maxn,0,0,(x2-x1)*(y2-y1)); } scanf("%d",&m); while(m--) { ll t; scanf("%I64d",&t); ll ans=0; ans+=A.getsum(t)*t*t; ans+=B.getsum(t)*t; ans+=C.getsum(t); printf("%I64d\n",ans); } } return 0; }
版权声明:本文为博主原创文章,未经博主允许不得转载。
标签:线段树
原文地址:http://blog.csdn.net/kirito_acmer/article/details/47281679