BZOJ 2731 Luogu P3219 [HNOI2012]三角形覆盖问题 (扫描线)
题目链接: (bzoj)https://www.lydsy.com/JudgeOnline/problem.php?id=2731
(luogu)https://www.luogu.org/problemnew/show/P3219
题解: 先讲一种复杂度明显不对但是本题数据跑得很快的做法: 先按底边\(y\)坐标排序,从下往上扫,每扫到一行链表维护当前的所有区间,另外再开个数组记录每个横坐标被覆盖的次数。复杂度\(O(\sum d_i)\)
然后ckw巨佬的做法: 按底边\(y\)坐标排序,找出所有三角形的最左点和最右点的\(x\)坐标作为关键点,按\(x\)坐标从左到右扫每一个关键点。
对于每相邻两个关键点之间的区间,找到所有包含它的三角形,那么每个三角形在此区间内一定是一个梯形,分类讨论(注意到我们已经按底边纵坐标排好序了)
如果上面的梯形顶端比下面的梯形顶端低,那么什么也不用做;
如果上面的梯形底端比下面的梯形顶端高,那么直接把下面梯形面积加入答案然后用上面梯形取代即可;
否则i,如果上面的梯形的底边比下面的梯形的右上点低,那么把两个梯形拼成一个梯形即可;
如果上面的梯形的底边比下面梯形的右上点高,那么计算下面梯形不被上面覆盖的面积(一个矩形减一个等腰直角三角形)加入答案,然后用上面梯形取代。
时间复杂度\(O(n^2)\)
(ckw: “这种SB题有什么做的必要么”)
代码
做法一
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cassert>
#include<algorithm>
#define llong long long
using namespace std;
const int N = 1e4;
const int C = 2e6;
struct Point
{
llong x,y;
Point() {}
Point(llong _x,llong _y) {x = _x,y = _y;}
};
struct Triangle
{
Point x; llong d;
bool operator <(const Triangle &arg) const {return x.y<arg.x.y;}
};
struct Element
{
int lb,rb,nxt,prv;
} cur[N+3];
Triangle a[N+3];
int num[C+3]; //±»¸²¸Ç´ÎÊý
int n,cnt;
int main()
{
scanf("%d",&n);
for(int i=1; i<=n; i++)
{
scanf("%lld%lld%lld",&a[i].x.x,&a[i].x.y,&a[i].d);
}
sort(a+1,a+n+1);
int j = 0; llong ans = 0ll,tmp = 0ll;
for(int i=0; i<=C; i++)
{
//±éÀúÁ´±í£¬É¾µô¸ÃɾµÄ
for(int k=cur[0].nxt; k!=0; k=cur[k].nxt)
{
num[cur[k].rb]--; if(num[cur[k].rb]==0) tmp--;
cur[k].rb--; if(cur[k].lb>=cur[k].rb) {cur[cur[k].prv].nxt = cur[k].nxt; cur[cur[k].nxt].prv = cur[k].prv;}
}
ans += tmp;
//¼ÓÈëÒÔ´ËΪµ×±ßµÄÈý½ÇÐÎ
while(j<n && a[j+1].x.y==i)
{
j++;
if(a[j].d==0) continue;
for(int k=a[j].x.x+1; k<=a[j].x.x+a[j].d; k++)
{
num[k]++; if(num[k]==1) tmp++;
}
cnt++; cur[cnt].prv = cur[0].prv; cur[cur[cnt].prv].nxt = cnt; cur[0].prv = cnt; cur[cnt].nxt = 0;
cur[cnt].lb = a[j].x.x; cur[cnt].rb = a[j].x.x+a[j].d;
}
ans += tmp;
}
for(int i=0; i<=C; i++) assert(num[i]==0);
printf("%lld",ans/2); if(ans&1) printf(".5"); else printf(".0");
return 0;
}
做法二
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cassert>
#include<algorithm>
#include<vector>
#define llong long long
using namespace std;
const int N = 1e4;
const int C = 2e6;
struct Point
{
llong x,y;
Point() {}
Point(llong _x,llong _y) {x = _x,y = _y;}
};
struct Triangle
{
Point x; llong d;
bool operator <(const Triangle &arg) const {return x.y<arg.x.y;}
};
Triangle a[N+3];
vector<int> ky;
int n,cnt;
llong sqr(llong x) {return x<0ll ? 0ll : x*x;}
int main()
{
scanf("%d",&n);
for(int i=1; i<=n; i++)
{
scanf("%lld%lld%lld",&a[i].x.x,&a[i].x.y,&a[i].d);
if(a[i].d==0) continue;
ky.push_back(a[i].x.x); ky.push_back(a[i].x.x+a[i].d);
}
sort(ky.begin(),ky.end());
ky.erase(unique(ky.begin(),ky.end()),ky.end());
sort(a+1,a+n+1);
llong ans = 0ll;
for(int i=1; i<ky.size(); i++)
{
int dn = 0,up = 0; //upl
for(int j=1; j<=n; j++)
{
if(a[j].d==0) continue;
if(a[j].x.x<=ky[i-1] && a[j].x.x+a[j].d>=ky[i])
{
if(dn==0 && up==0) {dn = a[j].x.y; up = a[j].x.y+a[j].d-(ky[i-1]-a[j].x.x);}
else
{
if(a[j].x.y>up)
{
ans += 2ll*(up-dn)*(ky[i]-ky[i-1])-sqr(ky[i]-ky[i-1]);
dn = a[j].x.y; up = a[j].x.y+a[j].d-(ky[i-1]-a[j].x.x);
}
else if(a[j].x.y+a[j].d-(ky[i-1]-a[j].x.x)>up)
{
ans += 2ll*(ky[i]-ky[i-1])*(a[j].x.y-dn);
if(a[j].x.y>up-(ky[i]-ky[i-1])) {ans -= sqr(a[j].x.y-(up-(ky[i]-ky[i-1])));}
dn = a[j].x.y; up = a[j].x.y+a[j].d-(ky[i-1]-a[j].x.x);
}
}
}
}
if(up==0 && dn==0);
else {ans += 2ll*(up-dn)*(ky[i]-ky[i-1])-sqr(ky[i]-ky[i-1]);}
}
printf("%lld",ans/2); if(ans&1) printf(".5"); else printf(".0");
return 0;
}
BZOJ 2731 Luogu P3219 [HNOI2012]三角形覆盖问题 (扫描线)的更多相关文章
- [HNOI2012]三角形覆盖问题
题面 二维平面中,给定 \(N\) 个等腰直角三角形(每个三角形的两条直角边分别平行于坐标轴,斜边从左上到右下).我们用三个非负整数 \((x, y, d)\) 来描述这样一个三角形,三角形三个顶点的 ...
- 【题解】三角形 [P1222] / 三角形覆盖问题 [HNOI2012] [P3219]
[题解]三角形 [P1222] / 三角形覆盖问题 [HNOI2012] [P3219] 传送门: 三角形 \(\text{[P1222]}\) 三角形覆盖问题 \(\text{[HNOI2012] ...
- [BZOJ 1535] [Luogu 3426]SZA-Template (KMP+fail树+双向链表)
[BZOJ 1535] [Luogu 3426]SZA-Template (KMP+fail树+双向链表) 题面 Byteasar 想在墙上涂一段很长的字符,他为了做这件事从字符的前面一段中截取了一段 ...
- [BZOJ 1336] [Balkan2002] Alien最小圆覆盖 【随机增量法】
题目链接:BZOJ - 1336 题目分析 最小圆覆盖有一个算法叫做随机增量法,看起来复杂度像是 O(n^3) ,但是可以证明其实平均是 O(n) 的,至于为什么我不知道= = 为什么是随机呢?因为算 ...
- Luogu 2764 最小路径覆盖问题 / Libre 6002 「网络流 24 题」最小路径覆盖 (网络流,最大流)
Luogu 2764 最小路径覆盖问题 / Libre 6002 「网络流 24 题」最小路径覆盖 (网络流,最大流) Description 给定有向图G=(V,E).设P是G的一个简单路(顶点不相 ...
- 【BZOJ2731】三角形覆盖问题
想象一条平行于\(y\)轴的扫描线,从低往高扫描.如何确定关键高度才能使每两个关键高度之间分割出的图形易于计算呢? 关键高度有:三角形底边高度.三角形上顶点高度.三角形交点的高度. 如此分割,我们 ...
- [Luogu 3224] HNOI2012 永无乡
[Luogu 3224] HNOI2012 永无乡 特别水一个平衡树题. 不认真的代价是调试时间指数增长. 我写的 SBT,因为 Treap 的 rand() 实在写够了. 用并查集维护这些点的关系, ...
- [HNOI 2012]三角形覆盖问题
Description 二维平面中,给定 N个等腰直角三角形(每个三角形的两条直角边分别 平行于坐标轴,斜边从左上到右下).我们用三个非负整数( x, y, d)来描 述这样一个三角形 ...
- BZOJ 3052/Luogu P4074 [wc2013]糖果公园 (树上带修莫队)
题面 中文题面,难得解释了 BZOJ传送门 Luogu传送门 分析 树上带修莫队板子题... 开始没给分块大小赋初值T了好一会... CODE #include <bits/stdc++.h&g ...
随机推荐
- poj2478(欧拉函数)
题目链接:https://vjudge.net/problem/POJ-2478 题意:给定n,输出集合中元素的数量,集合中的元素为最简小于1的分数,分子分母均属于[1,n-1]. 思路:理清题意后就 ...
- [转帖]Windows与Linux的命令行命令对比
Windows与Linux的命令行命令对比 https://www.cnblogs.com/sztom/p/10785140.html * Windows不区分大小写,Linux区分大小写的. sn ...
- awk 命令使用指南
一:awk 的执行流程 (1) 首先执行BEGIN{} 块中的初始化操作 (2) 然后从指定的数据文件中循环读取一个数据行 ( 自动更新 NF.NR.$0.$1....., 等内建变量的值) (3) ...
- property可以声明得位置
property可以声明的位置有4处 1 @interface处 2 扩展处 3 protocol处 4 分类处 其中分类处的property不会合成实例变量,并且编译器也不会自动合成实例变量
- 并发之AQS原理(二) CLH队列与Node解析
并发之AQS原理(二) CLH队列与Node解析 1.CLH队列与Node节点 就像通常医院看病排队一样,医生一次能看的病人数量有限,那么超出医生看病速度之外的病人就要排队. 一条队列是队列中每一个人 ...
- Python 描述符 (descriptor)
1.什么是描述符? 描述符是Python新式类的关键点之一,它为对象属性提供强大的API,你可以认为描述符是表示对象属性的一个代理.当需要属性时,可根据你遇到的情况,通过描述符进行访问他(摘自Pyth ...
- CentOS下配置Apache HTTPS
一.安装Apache支持SSL/TLS yum install mod_ssl openssl 二.创建证书 证书(Cerificate)的基本作用是将一个公钥和安全个体(个人.公司.组织等)的名字绑 ...
- SSH自动登录config文件配置
title: SSH自动登录config文件配置 comments: false date: 2019-08-19 19:29:13 description: 更方便的 ssh 操作??? categ ...
- 转载MySQL面试题
1.MySQL的复制原理以及流程 (1).复制基本原理流程 主:binlog线程--记录下所有改变了数据库数据的语句,放进master上的binlog中: 从:io线程--在使用start slave ...
- EC元素
'''判断title是否是一致,返回布尔值'''WebDriverWait(driver,10,0.1).until(EC.title_is("title_text")) '''判 ...