首页 > 其他 > 详细

UVA - 11983 - Weird Advertisement

时间:2015-11-28 14:55:55      阅读:271      评论:0      收藏:0      [点我收藏+]

算法提示

扫描线,线段树求矩形并的面积

 

题目大意

给了 n 的矩形,求被矩形覆盖 k 次及以上的点的个数。

 

做法分析

首先将 x2, y2 分别加 1 便转化为求面积的问题。

将 x 坐标离散化以后,用线段树维护区间 [l, r] 中,被覆盖 k 次的长度。

由于 k 最大为10,那么将大于等于 k 次都看成 k 次,于是线段树中每个结点只需要开一个长度为 11 的数组。

对于一个矩形 (x1, y1, x2, y2), 我们将它分成两条线段 (x1, x2, y1, 1) 和 (x1, x2, y2, -1)。

把 2n 条线按照 y 坐标从小到大排序,用扫描线依次扫每一条线段。

遇到 1 则表示区间 [x1, x2] 覆盖次数加 1; 遇到 -1 则表示区间 [x1, x2] 覆盖次数减 1。

由于每次查询都是整个区间的覆盖次数,即只看线段树根结点的信息,因此结点的懒标记不用下放,只需要通过左右儿子以及当前结点的懒标记来更新当前结点的信息。

详见代码 Update 函数,cover 表示整个区间被覆盖的次数,cnt[i] 表示被覆盖 i 次的长度。

每扫到一条线段,需要先计算这条线段与上一条线段 y 坐标的差值,乘上整个区间被覆盖 k 次的长度,得到被覆盖 k 次的面积,所有的面积和即使所有答案。

然后再用这条线段更新线段树。

需要注意的是,由于离散化了 x 坐标,所以离散后的每个点是左闭右开的区间,计算区间 [l, r] 的长度时,应该是 x[r+1] - x[l]。

 

参考代码

技术分享
  1 #include <cstdio>
  2 #include <cstring>
  3 #include <cmath>
  4 #include <queue>
  5 #include <algorithm>
  6 
  7 using namespace std;
  8 
  9 #define MAXN 60010
 10 #define INF 0x3f3f3f3f
 11 #define MAX(a,b) (a>b?a:b)
 12 #define MIN(a,b) (a<b?a:b)
 13 #define ABS(m) (m<0?-m:m)
 14 #define mo 1000000007
 15 typedef long long LL;
 16 
 17 int n,k,x[MAXN];
 18 
 19 struct RECTANGULAR
 20 {
 21     int x1,x2,y1,y2;
 22 }rect[MAXN];
 23 
 24 struct LINE
 25 {
 26     int x1,x2,y,t;
 27     bool operator<(const LINE &z) const{
 28         return y<z.y;
 29     }
 30 }line[MAXN];
 31 
 32 struct SegmentTree
 33 {
 34     int cover,cnt[11];
 35 }tree[MAXN*4];
 36 
 37 void Update(int i,int l,int r)
 38 {
 39     memset(tree[i].cnt,0,sizeof(tree[i].cnt));
 40     if(tree[i].cover>=k) tree[i].cnt[k]=x[r+1]-x[l];
 41     else if(l==r) tree[i].cnt[tree[i].cover]=x[r+1]-x[l];
 42     else{
 43         for(int j=0;j<=k;++j)
 44             tree[i].cnt[MIN(k,(j+tree[i].cover))]+=tree[i*2].cnt[j]+tree[i*2+1].cnt[j];
 45     }
 46 }
 47 
 48 void Build(int i,int l,int r)
 49 {
 50     tree[i].cover=0;
 51     memset(tree[i].cnt,0,sizeof(tree[i].cnt));
 52     tree[i].cnt[0]=x[r+1]-x[l];
 53     if(l==r) return;
 54     int mid=(l+r)>>1;
 55     Build(i*2,l,mid);
 56     Build(i*2+1,mid+1,r);
 57 }
 58 
 59 void Modify(int i,int l,int r,int s,int t,int val)
 60 {
 61     if(s<=l && r<=t){
 62         tree[i].cover+=val;
 63         Update(i,l,r);
 64         return;
 65     }
 66     int mid=(l+r)>>1;
 67     if(l<=t&&mid>=s) Modify(i*2,l,mid,s,t,val);
 68     if(mid<t&&r>=s) Modify(i*2+1,mid+1,r,s,t,val);
 69     Update(i,l,r);
 70 }
 71 
 72 void Init()
 73 {
 74     int i,l,r,mid;
 75     scanf("%d%d",&n,&k);
 76     for(i=1;i<=n;++i){
 77         scanf("%d%d%d%d",&rect[i].x1,&rect[i].y1,&rect[i].x2,&rect[i].y2);
 78         ++rect[i].x2; ++rect[i].y2;
 79         x[i]=rect[i].x1;
 80         x[i+n]=rect[i].x2;
 81     }
 82     sort(x+1,x+1+n*2);
 83     x[0]=unique(x+1,x+1+n*2)-x-1;
 84     for(i=1;i<=n;++i){
 85         line[i].y=rect[i].y1; line[i+n].y=rect[i].y2;
 86         line[i].t=1; line[i+n].t=-1;
 87         for(l=1,r=x[0];l<r;mid=(l+r)>>1,x[mid]<rect[i].x1?l=mid+1:r=mid);
 88         line[i].x1=line[i+n].x1=r;
 89         for(l=1,r=x[0];l<r;mid=(l+r)>>1,x[mid]<rect[i].x2?l=mid+1:r=mid);
 90         line[i].x2=line[i+n].x2=r;
 91     }
 92     sort(line+1,line+1+n*2);
 93 }
 94 
 95 LL Work()
 96 {
 97     int i;
 98     LL ans=0;
 99     for(i=1;i<=n*2;++i){
100         if(i>1 && line[i].y!=line[i-1].y)
101             ans+=1LL*tree[1].cnt[k]*(line[i].y-line[i-1].y);
102         Modify(1,1,x[0]-1,line[i].x1,line[i].x2-1,line[i].t);
103     }
104     return ans;
105 }
106 
107 int main()
108 {
109     int i,t;
110     for(scanf("%d",&t),i=1;i<=t;++i){
111         Init();
112         Build(1,1,x[0]-1);
113         printf("Case %d: %I64d\n",i,Work());
114     }
115     return 0;
116 }
View Code

 

题目连接

UVA - 11983 - Weird Advertisement

UVA - 11983 - Weird Advertisement

原文:http://www.cnblogs.com/orenjisora/p/5002567.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!