https://codeforc.es/contest/1194/problem/E

给5000条正常的(同方向不会重叠,也不会退化成点的)线段,他们都是平行坐标轴方向的,求能组成多少个矩形。

先进行坐标偏移,按水平线和垂直线分好类。

用扫描线的思路,从底部的水平线开始往上扫,先标记所有与该条水平线相交的竖直线,加入队列,给竖直线按y排序。

先把结束的竖直线undo掉,然后从这条水平线A的下一条水平线B开始,询问B线覆盖的区间中还有多少标记的竖直线。

注意要么偏移5001,要么把区间查询这里加个特判。防止越界到-1。

慢一点点的代码。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll; const int MAXN = 10001;
int bit[MAXN + 5]; inline int prefix_sum(int x) {
int res = 0;
for(; x; x -= x & -x)
res += bit[x];
return res;
} inline void add(int x, int v) {
for(; x <= MAXN; x += x & -x)
bit[x] += v;
} inline int range_sum(int l, int r) {
return prefix_sum(r) - prefix_sum(l - 1);
} struct Vertical_Line {
int x, y1, y2;
bool operator<(const Vertical_Line& vl) {
return x != vl.x ? x < vl.x : y1 < vl.y1;
}
} vl[5005];
int vtop; struct Vertical_Line_End {
int x, y;
bool operator<(const Vertical_Line_End& vle) {
return y < vle.y;
}
} vle[5005];
int vle_back, vle_front; struct Horizontal_Line {
int x1, x2, y;
bool operator<(const Horizontal_Line& hl) {
return y != hl.y ? y < hl.y : x1 < hl.x1;
}
} hl[5005];
int htop; int main() {
#ifdef Yinku
freopen("Yinku.in", "r", stdin);
//freopen("Yinku.out", "w", stdout);
#endif // Yinku
int n;
while(~scanf("%d", &n)) {
vtop = 0, htop = 0;
int x1, y1, x2, y2;
for(int i = 1; i <= n; i++) {
scanf("%d%d%d%d", &x1, &y1, &x2, &y2);
x1 += 5001, y1 += 5001, x2 += 5001, y2 += 5001;
if(x1 > x2)
swap(x1, x2);
if(y1 > y2)
swap(y1, y2);
if(x1 == x2) {
++vtop;
vl[vtop].x = x1;
vl[vtop].y1 = y1;
vl[vtop].y2 = y2;
} else {
++htop;
hl[htop].y = y1;
hl[htop].x1 = x1;
hl[htop].x2 = x2;
}
}
sort(vl + 1, vl + 1 + vtop);
sort(hl + 1, hl + 1 + htop);
ll ans = 0;
for(int hi = 1; hi <= htop; hi++) {
vle_front = 1;
vle_back = 0;
for(int vi = 1; vi <= vtop; vi++) {
if(vl[vi].x >= hl[hi].x1 && vl[vi].x <= hl[hi].x2 && vl[vi].y1 <= hl[hi].y && vl[vi].y2 >= hl[hi].y) {
add(vl[vi].x, 1);
++vle_back;
vle[vle_back].x = vl[vi].x;
vle[vle_back].y = vl[vi].y2;
}
}
sort(vle + 1, vle + 1 + vle_back);
int cury = hl[hi].y;
for(int hii = hi + 1; hii <= htop; hii++) {
while(vle_front <= vle_back && vle[vle_front].y < hl[hii].y) {
add(vle[vle_front].x, -1);
vle_front++;
}
int tmp = range_sum(hl[hii].x1, hl[hii].x2);
ans += (tmp * (tmp - 1) >> 1);
}
while(vle_front <= vle_back) {
add(vle[vle_front].x, -1);
vle_front++;
}
}
printf("%lld\n", ans);
}
}

其实一开始把竖直线也按y排序就省掉了后面的排序了的。快了一点点。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll; const int MAXN = 10001;
int bit[MAXN + 5]; inline int prefix_sum(int x) {
int res = 0;
for(; x; x -= x & -x)
res += bit[x];
return res;
} inline void add(int x, int v) {
for(; x <= MAXN; x += x & -x)
bit[x] += v;
} inline int range_sum(int l, int r) {
return prefix_sum(r) - prefix_sum(l - 1);
} struct Vertical_Line {
int x, y1, y2;
bool operator<(const Vertical_Line& vl) {
return y2 < vl.y2;
}
} vl[5005];
int vtop; struct Vertical_Line_End {
int x, y;
} vle[5005];
int vle_back, vle_front; struct Horizontal_Line {
int x1, x2, y;
bool operator<(const Horizontal_Line& hl) {
return y != hl.y ? y < hl.y : x1 < hl.x1;
}
} hl[5005];
int htop; int main() {
#ifdef Yinku
freopen("Yinku.in", "r", stdin);
//freopen("Yinku.out", "w", stdout);
#endif // Yinku
int n;
while(~scanf("%d", &n)) {
vtop = 0, htop = 0;
int x1, y1, x2, y2;
for(int i = 1; i <= n; i++) {
scanf("%d%d%d%d", &x1, &y1, &x2, &y2);
x1 += 5001, y1 += 5001, x2 += 5001, y2 += 5001;
if(x1 > x2)
swap(x1, x2);
if(y1 > y2)
swap(y1, y2);
if(x1 == x2) {
++vtop;
vl[vtop].x = x1;
vl[vtop].y1 = y1;
vl[vtop].y2 = y2;
} else {
++htop;
hl[htop].y = y1;
hl[htop].x1 = x1;
hl[htop].x2 = x2;
}
}
sort(vl + 1, vl + 1 + vtop);
sort(hl + 1, hl + 1 + htop);
ll ans = 0;
for(int hi = 1; hi <= htop; hi++) {
vle_front = 1;
vle_back = 0;
for(int vi = 1; vi <= vtop; vi++) {
if(vl[vi].x >= hl[hi].x1 && vl[vi].x <= hl[hi].x2 && vl[vi].y1 <= hl[hi].y && vl[vi].y2 >= hl[hi].y) {
add(vl[vi].x, 1);
++vle_back;
vle[vle_back].x = vl[vi].x;
vle[vle_back].y = vl[vi].y2;
}
}
//sort(vle + 1, vle + 1 + vle_back);
int cury = hl[hi].y;
for(int hii = hi + 1; hii <= htop; hii++) {
while(vle_front <= vle_back && vle[vle_front].y < hl[hii].y) {
add(vle[vle_front].x, -1);
vle_front++;
}
int tmp = range_sum(hl[hii].x1, hl[hii].x2);
ans += (tmp * (tmp - 1) >> 1);
}
while(vle_front <= vle_back) {
add(vle[vle_front].x, -1);
vle_front++;
}
}
printf("%lld\n", ans);
}
}

Codeforces - 1194E - Count The Rectangles - 扫描线的更多相关文章

  1. Codeforces 1194E. Count The Rectangles

    传送门 看到 $n<=5000$,直接暴力枚举左右两条竖线 然后考虑怎么计算高度在某个范围内,左端点小于等于某个值,右端点大于等于某个值的横线数量 直接用权值树状数组维护当前高度在某个区间内的横 ...

  2. Codeforces 1197E Count The Rectangles(树状数组+扫描线)

    题意: 给你n条平行于坐标轴的线,问你能组成多少个矩形,坐标绝对值均小于5000 保证线之间不会重合或者退化 思路: 从下到上扫描每一条纵坐标为y的水平的线,然后扫描所有竖直的线并标记与它相交的线,保 ...

  3. Educational Codeforces Round 68 E. Count The Rectangles

    Educational Codeforces Round 68 E. Count The Rectangles 传送门 题意: 给出不超过\(n,n\leq 5000\)条直线,问共形成多少个矩形. ...

  4. Codeforces 372 B. Counting Rectangles is Fun

    $ >Codeforces \space 372 B.  Counting Rectangles is Fun<$ 题目大意 : 给出一个 \(n \times m\) 的 \(01\) ...

  5. codeforces 713B B. Searching Rectangles(二分)

    题目链接: B. Searching Rectangles time limit per test 1 second memory limit per test 256 megabytes input ...

  6. codeforces D. Count Good Substrings

    http://codeforces.com/contest/451/problem/D 题意:给你一个字符串,然后找出奇数和偶数长度的子串的个数,这些字串符合,通过一些连续相同的字符合并后是回文串. ...

  7. CodeForces - 1189E Count Pairs(平方差)

    Count Pairs You are given a prime number pp, nn integers a1,a2,…,ana1,a2,…,an, and an integer kk. Fi ...

  8. CodeForces 1216C(假的计算几何+扫描线)

    传送门 •题意 给你三个矩形,依次编号为 1,2,3: 判断 矩形1 是否被 矩形2 和 矩形3 完全覆盖: 如果没有完全覆盖,输出 "YES",反之,输出 "NO&qu ...

  9. Codeforces 1188B - Count Pairs(思维题)

    Codeforces 题面传送门 & 洛谷题面传送门 虽说是一个 D1B,但还是想了我足足 20min,所以还是写篇题解罢( 首先注意到这个式子里涉及两个参数,如果我们选择固定一个并动态维护另 ...

随机推荐

  1. tf.clip_by_global_norm

    首先明白这个事干嘛的,在我们做求导的时候,会遇到一种情况,求导函数突然变得特别陡峭,是不是意味着下一步的进行会远远高于正常值,这个函数的意义在于,在突然变得陡峭的求导函数中,加上一些判定,如果过于陡峭 ...

  2. 211-基于FMC的ADC-DAC子卡

    基于FMC的ADC-DAC子卡 一.板卡概述 FMC-1AD-1DA-1SYNC是我司自主研发的一款1路1G AD采集.1路2.5G DA回放的FMC.1路AD同步信号子卡.板卡采用标准FMC子卡架构 ...

  3. MYSQL学习笔记——连接以及存储过程

    连接 当我们需要从多个表查询数据时,我们就需要使用到连接操作,mysql支持内连接,左连接以及右连接三种连接方式. 数据库准备 首先我们创建两个表t1, t2: create table t1(i1 ...

  4. 1146. Topological Order (25)

    This is a problem given in the Graduate Entrance Exam in 2018: Which of the following is NOT a topol ...

  5. php内置函数分析之trim()

    官方手册中: 类似函数还有两个:ltrim() 和 rtrim().分别处理字符串的左侧.右侧. trim()的具体实现位于:ext/standard/string.c /* {{{ proto st ...

  6. 印度黑客滥用移动设备管理服务MDM监视iPhone用户

    两周前首次亮相的印度高度针对性的移动恶意软件广告系列已被发现是针对多种平台的广泛广告系列的一部分,包括Windows设备,也可能是Android. 在本月早些时候,Talos威胁情报部门的研究人员发现 ...

  7. flask之路径与函数的映射

    一:运行报错 OSError: [Errno 98] Address already in use:5000端口可能被占 lsof -i:端口号  查看端口被那个进程使用,结果是python3.5 k ...

  8. TPS、QPS和系统吞吐量的区别和理解

    参考:https://blog.csdn.net/u010889616/article/details/83245695 一.QPS/TPSQPS:Queries Per Second意思是“每秒查询 ...

  9. Check the port occupy on Mac OSX

    Check the port occupy on Mac OSX lsof -i :7070 COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME si ...

  10. c#代码规则,C#程序中元素的命名规范

    俩种命名方法 1.Pascal 命名法,第一个字母大写其它字母小写Userid 2.Camel命名法,所有单第一方写大写,其它小写,骆峰命名法,userId C#程序中元素的命名规范项目名:公司名.项 ...