什么,扫描线需要线段树?

那我第一个不干啊(其实是不会写)

这里介绍一种裸的扫描线:

我们根据x排序,对于相等的 \(x\) ,将 \(y\) 进入和退出分类讨论,然后全部放进set里面.每次 \(x\) 不相等的时候,答案就是 (现在y覆盖的乘以(现在的x-以前的x))

具体的判断方法:

1.y的判断:

将每个长方形的上方点记做出口,下方点记做入口.用一个set记录在某区间内所有的 \(y\) 值.每次从下往上扫,如果某个y是入口就将 \(sz\) +1,否则就将 \(sz\) -1.如果 \(sz\)==0 的时候就将你整个区间的值加到re里面



如图,每次x变的时候只需要保存中间y的值,然后用移动的x乘y就好了

注:我保存y进入和退出状态的原因就是为了记录中间是否有空位.可以发现,如果中间有空位,那么证明所有进入的点已经退出了,所以那一段不需要加上去(不懂可以画一下图)

long long query_up(){
long long re = 0,prev = -1,sz = 0;
for (multiset<pair<long long,bool> >::iterator i=se.begin();i!=se.end();++i){
pair<long long,bool> now = *i;
if (sz==0) {prev = now.f;sz++;}
else if (now.s) sz++;
else sz--;
if (sz==0) re+=(now.f-prev);//如果现在所以的y都已经出去了,那么答案就是最后一个y的出口-第一个y的入口
}
return re;
}

想到了这点以后这题的难点基本上就解决了.

因为有负数,我将每个数都加上了1e8,这样就可以完全不管负数了

不开long long见祖宗

完整代码:

#include <iostream>
#include <set>
#include <algorithm>
#include <iterator>
#include <utility>
using namespace std;
const long long MAXN = 1e5+5;
#define pp pair<long long,long long>
#define f first
#define s second
long long n,ans = 0;
multiset<pair<long long,bool> > se;
struct Edge{
long long x,y; bool in,in2;
}edge[MAXN*4];
Edge add_edge(long long a, long long b, bool bo,bool bo2){
Edge tmp;
tmp.x = a;
tmp.y = b;
tmp.in = bo;
tmp.in2 = bo2;
return tmp;
}
bool sorted(Edge a, Edge b){
return a.x<b.x;
}
long long query_up(){
long long re = 0,prev = -1,sz = 0;
for (multiset<pair<long long,bool> >::iterator i=se.begin();i!=se.end();++i){
pair<long long,bool> now = *i;
if (sz==0) {prev = now.f;sz++;}
else if (now.s) sz++;
else sz--;
if (sz==0) re+=(now.f-prev);
}
return re;
}
int main(){
cin >> n;
for (long long i=0;i<n;i++){
long long a,b,c,d; cin >> a >>b >> c >> d;
a+=1e8;b+=1e8;c+=1e8;d+=1e8;
edge[4*i] = add_edge(a,b,1,0);
edge[4*i+1] = add_edge(a,d,1,1);
edge[4*i+2] = add_edge(c,b,0,0);
edge[4*i+3] = add_edge(c,d,0,1);
//两种状态,第一种表示x变不变,第二种表示y变不变
}
sort(edge,edge+4*n,sorted);
long long prev = 0;
for (long long i=0;i<4*n;i++){
if (edge[i].x!=prev){//如果x变了
if (se.size()) ans += (edge[i].x-prev)*query_up();
prev = edge[i].x;
}
if (edge[i].in==1) se.insert(make_pair(edge[i].y,edge[i].in2));//如果这点是进入的点,就将y加入set
else se.erase(se.find(make_pair(edge[i].y,edge[i].in2)));
//否则将y扔出set
}
cout << ans;
}

留一组测试数据造福后人

3
3 7 7 3
1 5 5 1
2 2 7 -2

答案45

最新文章

  1. Qt——浅谈样式表
  2. iOS中“返回”操作相关
  3. [LintCode] Length of Last Word 求末尾单词的长度
  4. 使用DB4o做一个.Net版的website(一)环境
  5. Java设计模式-状态模式(State)
  6. iOS 图片拉伸的解释
  7. centos 6安装redis 2.8.19
  8. NeHe OpenGL教程 第四十一课:体积雾气
  9. 淘宝API Nodejs的实现
  10. 2014 Multi-University Training Contest 2
  11. EditPlus自动补全、模板配置
  12. 开源API测试工具 Hitchhiker v0.6更新 - 改进压力测试
  13. [PHP开发] phpmailer问题 错误原因: Could not instantiate mail function
  14. 使用everything把一个文件夹里(包含子目录)的所有图片拷贝到另一个文件夹
  15. C++:位操作基础篇之位操作全面总结
  16. 【springboot】【socket】spring boot整合socket,实现服务器端两种消息推送
  17. Spring Boot的@SpringBootApplication无法引入的问题
  18. day038 navicat pymysql
  19. [转][CentOS]开机时
  20. python的基础socket知识

热门文章

  1. pycharm 设置项目的编译器
  2. MFC之拆分窗口
  3. jupiter的@TempDir 等不生效
  4. 每天一点点之vue框架开发 - vue坑-input 的checked渲染问题
  5. MFC 屏蔽esc跟enter键
  6. 数据库连接池DBCP的使用
  7. 七、CI框架之分配变量数组,循环输出
  8. foreach —(遍历数组或循环中的字符,以获取信息)
  9. 服务器io资源查看
  10. SeetaFaceQt:Qt多线程