1845: [Cqoi2005] 三角形面积并

Time Limit: 3 Sec  Memory Limit: 64 MB
Submit: 1664  Solved: 443
[Submit][Status][Discuss]

Description

给出n个三角形,求它们并的面积。

Input

第一行为n(N < = 100), 即三角形的个数
以下n行,每行6个整数x1, y1, x2, y2, x3, y3,代表三角形的顶点坐标。坐标均为不超过10 ^ 6的实数,输入数据保留1位小数

Output

输出并的面积u, 保留两位小数

Sample Input

2

0.0 0.0 2.0 0.0 1.0 1.0

1.0 0.0 3.0 0.0 2.0 1.0


Sample Output

1.75

HINT

Source

[Submit][Status][Discuss]

HOME
Back

Claris的题解

求出所有交点后从左往右扫描线,用每段的中位线去截所有三角形,算出长度并后乘以该段长度即可,时间复杂度\(O(n^3\log n)\)。

#include<bits/stdc++.h>
#define rg register
#define il inline
#define co const
template<class T>il T read(){
rg T data=0,w=1;rg char ch=getchar();
while(!isdigit(ch)) {if(ch=='-') w=-1;ch=getchar();}
while(isdigit(ch)) data=data*10+ch-'0',ch=getchar();
return data*w;
}
template<class T>il T read(rg T&x) {return x=read<T>();}
typedef long long ll;
using namespace std; co double eps=1e-9,INF=1e6;
il int sig(double x) {return abs(x)<eps?0:(x>0?1:-1);}
struct P{double x,y;};
il bool cmp(co P&u,co P&v) {return u.x<v.x;}
il P operator+(co P&u,co P&v) {return (P){u.x+v.x,u.y+v.y};}
il P operator-(co P&u,co P&v) {return (P){u.x-v.x,u.y-v.y};}
il P operator*(co P&u,double k) {return (P){u.x*k,u.y*k};}
il double cross(co P&u,co P&v) {return u.x*v.y-u.y*v.x;}
il bool has_intersection(co P&a,co P&b,co P&p,co P&q){
return sig(cross(b-a,p-a))*sig(cross(b-a,q-a))<0&&
sig(cross(q-p,a-p))*sig(cross(q-p,b-p))<0;
}
il P line_intersection(co P&a,co P&b,co P&p,co P&q){
return a+(b-a)*(cross(p-a,q-p)/cross(b-a,q-p));
} co int N=300;
int n,m;
P tri[N][4],seg[N];
double px[N*N],ans;
double cal(double x){
P D=(P){x,-INF},U=(P){x,INF};
int m=0;
for(int i=0,k=0;i<n;++i,k=0){
double y[2];
for(int j=0;j<3;++j)if(has_intersection(tri[i][j],tri[i][j+1],D,U))
y[k++]=line_intersection(tri[i][j],tri[i][j+1],D,U).y;
if(k) seg[m++]=(P){min(y[0],y[1]),max(y[0],y[1])};
}
if(m>1) sort(seg,seg+m,cmp);
double l=-INF,r=-INF,t=0;
for(int i=0;i<m;++i){
if(sig(seg[i].x-r)>0) t+=r-l,l=seg[i].x;
r=max(r,seg[i].y);
}
return t+r-l;
}
int main(){
// freopen(".in","r",stdin),freopen(".out","w",stdout);
read(n);
for(int i=0;i<n;++i){
for(int j=0;j<3;++j)
scanf("%lf%lf",&tri[i][j].x,&tri[i][j].y),px[m++]=tri[i][j].x;
tri[i][3]=tri[i][0];
}
for(int i=0;i<n;++i)for(int j=0;j<i;++j)
for(int k=0;k<3;++k)for(int l=0;l<3;++l)
if(has_intersection(tri[i][k],tri[i][k+1],tri[j][l],tri[j][l+1]))
px[m++]=line_intersection(tri[i][k],tri[i][k+1],tri[j][l],tri[j][l+1]).x;
sort(px,px+m);
for(int i=1;i<m;++i)if(sig(px[i]-px[i-1]))
ans+=(px[i]-px[i-1])*cal((px[i]+px[i-1])/2);
return printf("%.2lf\n",ans-eps),0;
}

Picture

Language:Default
Picture
Time Limit: 2000MS Memory Limit: 10000K
Total Submissions: 14427 Accepted: 7542

Description

A number of rectangular posters, photographs and other pictures of the same shape are pasted on a wall. Their sides are all vertical or horizontal. Each rectangle can be partially or totally covered by the others. The length of the boundary of the union of all rectangles is called the perimeter.



Write a program to calculate the perimeter. An example with 7 rectangles is shown in Figure 1.



The corresponding boundary is the whole set of line segments drawn in Figure 2.



The vertices of all rectangles have integer coordinates.

Input

Your program is to read from standard input. The first line contains the number of rectangles pasted on the wall. In each of the subsequent lines, one can find the integer coordinates of the lower left vertex and the upper right vertex of each rectangle. The values of those coordinates are given as ordered pairs consisting of an x-coordinate followed by a y-coordinate.



0 <= number of rectangles < 5000

All coordinates are in the range [-10000,10000] and any existing rectangle has a positive area.

Output

Your program is to write to standard output. The output must contain a single line with a non-negative integer which corresponds to the perimeter for the input rectangles.

Sample Input

7
-15 0 5 10
-5 8 20 25
15 -4 24 14
0 -6 16 4
2 15 10 22
30 10 36 20
34 0 40 16

Sample Output

228

Source

给出多个矩形坐标,求所有矩形的组合体的周长

A_Mango的题解

这道题的突破口是线扫描,假想一条垂直于y轴的线从下往上扫描,以矩形x轴方向的边为事件,这样只要知道当前发生事件时矩形的覆盖x轴的长度(为了计算x轴方向的边),以及由几块孤立的区域组成(为了计算y轴方向的边),但是问题就是如何在每次更新事件时更新这两个属性

这就到了线段树出场,因为如果要维护这2个属性,必须要在矩形下边的边时加入它,在上边时把它删除,能快速做到对一个线段快速修改就是线段树了,而且对于维护一个区域内的线段的总长度,以及孤立的线段数量,它也不难实现,但这时候问题来了,坐标的范围是-10000~10000,正常用这个坐标来更新线段树的话速度可能不够。所以最好的办法就是先对矩形边的x坐标离散化(不过本题中如果数据不太变态,不离散化估计也能过)

线段树的维护:这也是一个难点,越用这东西越觉得它有很多东西值得钻研。本题中要维护的2个线段树属性

  1. 覆盖的总线段长

    因为对同个区域插入多次,他的总长度还是不变,对一个区域删除的次数要等于他插入的次数才能把区域中的长度减少,所以要在每个节点加上覆盖次数cover
  2. 孤立线段的数量

    因为要判断2个子区域是否相连,加上bl,br记录当前节点左右边界是否被覆盖

时间复杂度\(O(n \log n)\)

#include<iostream>
#include<algorithm>
#define rg register
#define il inline
#define co const
template<class T>il T read(){
rg T data=0,w=1;rg char ch=getchar();
while(!isdigit(ch)) {if(ch=='-') w=-1;ch=getchar();}
while(isdigit(ch)) data=data*10+ch-'0',ch=getchar();
return data*w;
}
template<class T>il T read(rg T&x) {return x=read<T>();}
typedef long long ll;
using namespace std; co int N=2e4+1,INF=0x3f3f3f3f;
int n,Max=-INF,Min=INF,tot,ans,pre;
struct P{
int l,r,h,k;
il bool operator<(co P&p)co {return h!=p.h?h<p.h:k>p.k;}
}a[N];
struct T{
int sum,num,len;
bool l,r;
}t[N*4];
il void add(int l,int r,int h,int k){
a[++tot].l=l,a[tot].r=r,a[tot].h=h,a[tot].k=k;
}
#define lc (p<<1)
#define rc (p<<1|1)
il void work(int p,int l,int r){
if(t[p].sum) t[p].num=t[p].l=t[p].r=1,t[p].len=r-l+1;
else if(l==r) t[p].len=t[p].num=t[p].l=t[p].r=0;
else{
t[p].len=t[lc].len+t[rc].len;
t[p].num=t[lc].num+t[rc].num;
if(t[lc].r&&t[rc].l) --t[p].num;
t[p].l=t[lc].l,t[p].r=t[rc].r;
}
}
void change(int p,int l,int r,int L,int R,int k){
if(L<=l&&r<=R) return t[p].sum+=k,work(p,l,r);
int mid=l+r>>1;
if(L<=mid) change(lc,l,mid,L,R,k);
if(R>mid) change(rc,mid+1,r,L,R,k);
work(p,l,r);
}
int main(){
// freopen(".in","r",stdin),freopen(".out","w",stdout);
read(n);
for(int i=1,x1,y1,x2,y2;i<=n;++i){
read(x1),read(y1),read(x2),read(y2);
Max=max(Max,max(x1,x2)),Min=min(Min,min(x1,x2));
add(x1,x2,y1,1),add(x1,x2,y2,-1);
}
if(Min<=0){
for(int i=1;i<=tot;++i) a[i].l+=1-Min,a[i].r+=1-Min;
Max-=Min; // len-1
}
sort(a+1,a+tot+1);
for(int i=1;i<=tot;++i){
change(1,1,Max,a[i].l,a[i].r-1,a[i].k);
while(a[i].h==a[i+1].h&&a[i].k==a[i+1].k)
++i,change(1,1,Max,a[i].l,a[i].r-1,a[i].k);
ans+=abs(t[1].len-pre),pre=t[1].len;
ans+=t[1].num*(a[i+1].h-a[i].h)*2;
}
printf("%d\n",ans);
return 0;
}

CQOI2005 三角形面积并 和 POJ1177 Picture的更多相关文章

  1. bzoj 1845: [Cqoi2005] 三角形面积并 扫描线

    1845: [Cqoi2005] 三角形面积并 Time Limit: 3 Sec  Memory Limit: 64 MBSubmit: 848  Solved: 206[Submit][Statu ...

  2. BZOJ 1845: [Cqoi2005] 三角形面积并 [计算几何 扫描线]

    1845: [Cqoi2005] 三角形面积并 Time Limit: 3 Sec  Memory Limit: 64 MBSubmit: 1151  Solved: 313[Submit][Stat ...

  3. [CQOI2005]三角形面积并

    [CQOI2005]三角形面积并 题目大意: 求\(n(n\le100)\)个三角形的面积并. 思路: 自适应辛普森法,玄学卡精度可过. 源代码: #include<cmath> #inc ...

  4. 【BZOJ1845】[Cqoi2005] 三角形面积并 几何+扫描线

    [BZOJ1845][Cqoi2005] 三角形面积并 Description 给出n个三角形,求它们并的面积. Input 第一行为n(N < = 100), 即三角形的个数 以下n行,每行6 ...

  5. BZOJ1845 [Cqoi2005] 三角形面积并 扫描线 计算几何

    欢迎访问~原文出处——博客园-zhouzhendong 去博客园看该题解 题目传送门 - BZOJ1845 题意概括 给出n个三角形,求其面积并. 题解 有一个很经典的扫描线题目:矩形面积并.那个比较 ...

  6. BZOJ1845 : [Cqoi2005] 三角形面积并

    求出所有交点后从左往右扫描线,用每段的中位线去截所有三角形,算出长度并后乘以该段长度即可,时间复杂度$O(n^3\log n)$. #include<cstdio> #include< ...

  7. BZOJ 1845: [Cqoi2005] 三角形面积并 (辛普森积分)

    大力辛普森积分 精度什么的搞了我好久- 学到了Simpson的一个trick 深度开11,eps开1e-4.跑的比有些扫描线还快- CODE #include <bits/stdc++.h> ...

  8. UVa 11437:Triangle Fun(计算几何综合应用,求直线交点,向量运算,求三角形面积)

    Problem ATriangle Fun Input: Standard Input Output: Standard Output In the picture below you can see ...

  9. [POJ1177]Picture

    [POJ1177]Picture 试题描述 A number of rectangular posters, photographs and other pictures of the same sh ...

随机推荐

  1. C/C++ 多线程(程序猿面试重点)CodeBlocks-CB的pthreads使用

    C++ 多线程 本文主要讲一下C++多线程 线程好处 ·使用线程可以把占据长时间的程序中的任务放到后台去处理 ·程序的运行速度可能加快 可以释放一些珍贵的资源如内存占用等等. 但是多线程是为了同步完成 ...

  2. Java创建线程的两种方法

    大多数情况,通过实例化一个Thread对象来创建一个线程.Java定义了两种方式: 实现Runnable 接口: 可以继承Thread类. 下面的两小节依次介绍了每一种方式. 实现Runnable接口 ...

  3. Spring初解

    1,关于spring容器: spring容器是Spring的核心,该 容器负责管理spring中的java组件, ApplicationContext ctx  = new ClassPathXmlA ...

  4. 038 Android Magicindicator开源框架实现viewpager底部圆形指示器

    1.Magicindicator介绍 Magicindicator是一个强大.可定制.易扩展的 ViewPager 指示器框架.是ViewPagerIndicator.TabLayout.PagerS ...

  5. python学习-54 正则表达式2

    re模块 之分组 >>> import re >>> re.findall("ab|c","sdfab|csdf") ['a ...

  6. BBS项目架构

    数据库设计 用户表(用的是auth_user那张表,通过自定义表继承AbstractUser) phone 电话 avatar 头像 create_time 创建时间#外键 blog 一对一个人站点表 ...

  7. 如何将本地的项目添加到github上

    参考链接:http://note.youdao.com/noteshare?id=d0b7990a83b024b0172b6d5c5617a8d0&sub=659F216B9046420991 ...

  8. MAC帧封装

    通过控制台输入一段文字,输出MAC帧的2进制和16进制的字符串,主要是求FCS.这里只考虑单帧的情况,即只考虑输入数据在1字节~1500字节之间的情况,对于更长的数据暂不考虑. 1.MAC帧基本格式 ...

  9. 全面优化MySQL

    MySQL性能瓶颈原因 硬件.系统因素 CPU 磁盘I/O 网络性能 操作系统争用 MySQL相关因素 数据库设计 索引.数据类型 应用程序性能 特定请求.短时事务 配置变量 缓冲区.高速缓存.Inn ...

  10. 升级win10 1903版后,vmware打开虚拟机黑屏的解决办法

    按照网上给的方法(1-3),又增加了几步(从4开始,只在我自己电脑上实践过): 1. 打开cmd,执行以下命令 netsh winsock reset 2. 重启电脑 3. 以管理员身份执行vmwar ...