HDU-1255 覆盖的面积(线扫描)

链接:http://acm.hdu.edu.cn/showproblem.php?pid=1255

中文题意就不用再说了。

这是赤裸裸的线扫描问题,唯一不同的就是求得面积是覆盖超过两次的面积的大小。其实就是求覆盖面积里面多一个变量来存储覆盖一次的长度(HDU 1542)。

这里有一个小小的坑点,要注意if语句判断的顺序。

  1 #include<cstdio>
  2 #include<algorithm>
  3 using namespace std;
  4 
  5 const int maxn=2018;
  6 int n;
  7 double x[maxn*2];
  8 
  9 struct Line
 10 {
 11     double x1,x2,y;
 12     operator<(const Line &a)const
 13     {
 14         return y<a.y;
 15     }
 16     int flag;
 17 }line[maxn*2];
 18 
 19 struct Trie
 20 {
 21     int l,r;///线段树的左右端点
 22     double dl,dr;///左右端点的大小
 23     double len1,len2;///覆盖一次与两次的长度
 24     int cov;///被覆盖的次数
 25 }a[maxn*4];
 26 
 27 void Get_Len(int id)
 28 {
 29     if(a[id].cov>0)
 30         a[id].len1=a[id].dr-a[id].dl;
 31     else if(a[id].l+1==a[id].r)
 32         a[id].len1=0;
 33     else
 34         a[id].len1=a[id*2].len1+a[id*2+1].len1;
 35 
 36     if(a[id].cov>1)
 37         a[id].len2=a[id].dr-a[id].dl;
 38     else if(a[id].l+1==a[id].r)///(①)
 39         a[id].len2=0;
 40     else if(a[id].cov==1)///(②)
 41                         ///① ②两个if语句交换了之后就是WA
 42                         ///先判断①就是防止②语句的id*2可能不存在
 43         a[id].len2=a[id*2].len1+a[id*2+1].len1;
 44     else
 45         a[id].len2=a[id*2].len2+a[id*2+1].len2;
 46 }
 47 void Build(int id,int l,int r)
 48 {
 49     a[id].cov=0;
 50     a[id].dl=x[l];
 51     a[id].dr=x[r];
 52     a[id].l=l;
 53     a[id].r=r;
 54     a[id].len1=0;
 55     a[id].len2=0;
 56     if(l+1==r)
 57         return ;
 58     int mid=(l+r)/2;
 59     Build(id*2,l,mid);
 60     Build(id*2+1,mid,r);
 61 
 62 }
 63 void Updata(int id,Line e)
 64 {
 65     if(a[id].dl==e.x1&&a[id].dr==e.x2)
 66     {
 67         a[id].cov+=e.flag;
 68         Get_Len(id);
 69         return ;
 70     }
 71 
 72     if(a[id*2].dr>=e.x2)
 73         Updata(id*2,e);
 74     else if(a[id*2+1].dl<=e.x1)
 75         Updata(id*2+1,e);
 76     else
 77     {
 78         Line tep=e;
 79         tep.x2=a[id*2].dr;
 80         Updata(id*2,tep);
 81 
 82         tep=e;
 83         tep.x1=a[id*2+1].dl;
 84         Updata(id*2+1,tep);
 85     }
 86     Get_Len(id);
 87 }
 88 
 89 int main()
 90 {
 91     int t;
 92     scanf("%d",&t);
 93     while(t--)
 94     {
 95         scanf("%d",&n);
 96         int cnt=0;
 97         for(int i=1;i<=n;i++)
 98         {
 99             double x1,y1,x2,y2;
100             scanf("%lf %lf %lf %lf",&x1,&y1,&x2,&y2);
101             cnt++;
102             line[cnt].x1=x1;
103             line[cnt].x2=x2;
104             line[cnt].y=y1;
105             line[cnt].flag=1;
106             x[cnt]=x1;
107 
108             cnt++;
109             line[cnt].x1=x1;
110             line[cnt].x2=x2;
111             line[cnt].y=y2;
112             line[cnt].flag=-1;
113             x[cnt]=x2;
114         }
115         sort(x+1,x+1+cnt);
116         sort(line+1,line+1+cnt);
117         Build(1,1,cnt);
118         Updata(1,line[1]);
119         double ans=0;
120         for(int i=2;i<=cnt;i++)
121         {
122 
123             ans+=a[1].len2*(line[i].y-line[i-1].y);
124             Updata(1,line[i]);
125         }
126         printf("%.2f\n",ans);
127     }
128     return 0;
129 }

 

转载于:https://www.cnblogs.com/Y-Meng/p/8496652.html

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值