Counting Intersections

题目链接:

http://acm.split.hdu.edu.cn/showproblem.php?pid=5862

Description


Given some segments which are paralleled to the coordinate axis. You need to count the number of their intersection.
The input data guarantee that no two segments share the same endpoint, no covered segments, and no segments with length 0.

Input


The first line contains an integer T, indicates the number of test case.
The first line of each test case contains a number n(1

Output


For each test case, output one line, the number of intersection.

Sample Input


2
4
1 0 1 3
2 0 2 3
0 1 3 1
0 2 3 2
4
0 0 2 0
3 0 3 2
3 3 1 3
0 3 0 2

Sample Output


4
0

Source


2016 Multi-University Training Contest 10


##题意:

给出平面上N条平行于坐标轴的线段. 保证线段没有公共端点,没有覆盖.
求N条线段有多少个交点.


##题解:

对于所有线段按照x坐标排序,将y坐标离散化,在从左到右遍历线段的过程中:
遇到水平线段的左端点时,将其对应y坐标在树状数组中的值+1.
遇到水平线段的(右端点+1)时,将其对应y坐标在树状数组中的值-1.
遇到竖直线段时,查询其纵坐标区间的和,即为这条竖直线段能产生的交点的个数.

注意的几点:
以下代码将水平线段当成两个点来存储,竖直线段当成一个点来存储.
离散化时只需要对y坐标离散.
在排序时,x坐标是第一优先级,其次应该按先水平再竖直排序. 这样可以保证'T'字型情况得到处理.
应该在遇到水平线段右端点+1的位置时才将树状数组中的值-1.
树状数组中的n为需要处理的纵坐标的个数,不是输入的n,务必区分开来.

比赛时想的是区间更新+单点查询,即先将在某条水平线段横坐标区间内竖直线段进行区间更新,这样一来对水平线段的排序就不太好处理,比如投影区间覆盖的情况.
贴一个[线段树+扫描线](http://www.cnblogs.com/zhangchengc919/p/5784725.html)的解法,过几天学习一下:


##代码:
``` cpp
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define LL long long
#define eps 1e-8
#define maxn 201000
#define mod 100000007
#define inf 0x3f3f3f3f
#define mid(a,b) ((a+b)>>1)
#define IN freopen("in.txt","r",stdin);
using namespace std;

struct node {

int type; // 0横 1竖

int x, y1,y2;

node() {}

node(int a,int b,int c,int d) {type=a;x=b;y1=c;y2=d;}

bool operator < (const node& b) const {

if(x == b.x) return type < b.type; //先处理横向

return x < b.x;

}

}p[maxn];

int n, cnt;

int c[maxn];

int lowbit(int x) {

return x & (-x);

}

int newn; // 区别于n

void update(int x, int d) {

while(x <=newn) {

c[x] += d;

x += lowbit(x);

}

}

int get_sum(int x) {

LL ret = 0;

while(x > 0) {

ret += c[x];

x -= lowbit(x);

}

return ret;

}

map<int, int> mp;

int pos[maxn], pos_cnt;

int main(int argc, char const *argv[])

{

//IN;

int t; cin >> t;
while(t--)
{
scanf("%d", &n);
mp.clear();
cnt = 0; pos_cnt = 0; for(int i=1; i<=n; i++) {
int x1,y1,x2,y2; scanf("%d %d %d %d",&x1,&y1,&x2,&y2);
if(y1 == y2) { // hor
if(x1 > x2) swap(x1, x2);
p[++cnt] = node(0, x1, y1, +1);
p[++cnt] = node(0, x2+1, y1, -1); //右端点的下一个位置
pos[++pos_cnt] = y1;
} else { // ver
if(y1 > y2) swap(y1, y2);
p[++cnt] = node(1, x1, y1, y2);
pos[++pos_cnt] = y1;
pos[++pos_cnt] = y2;
}
} sort(pos+1, pos+1+pos_cnt);
int counts = 0;
for(int i=1; i<=pos_cnt; i++) {
if(!mp[pos[i]]) mp[pos[i]] = ++counts;
} sort(p+1, p+1+cnt); LL ans = 0;
newn = counts; //务必与n区分开来
memset(c, 0, sizeof(c));
for(int i=1; i<=cnt; i++) {
if(p[i].type == 0) { // hor
update(mp[p[i].y1], p[i].y2);
} else { // ver
ans += get_sum(mp[p[i].y2]) - get_sum(mp[p[i].y1]-1);
}
} printf("%lld\n", ans);
} return 0;

}

HDU 5862 Counting Intersections (树状数组)的更多相关文章

  1. HDU 3887 Counting Offspring (树状数组+人工模拟栈)

    对这棵树DFS遍历一遍,同一节点入栈和出栈之间访问的节点就是这个节点的子树. 因此节点入栈时求一次 小于 i 的节点个数 和,出栈时求一次 小于 i 的节点个数 和,两次之差就是答案. PS.这题直接 ...

  2. HDU 5862(离散化+树状数组)

    Problem Counting Intersections 题目大意 给定n条水平或竖直的线段,统计所有线段的交点个数. (n<=100000) 解题分析 首先将线段离散化. 然后将所有线段按 ...

  3. HDU 5862 Counting Intersections(离散化+树状数组)

    HDU 5862 Counting Intersections(离散化+树状数组) 题目链接http://acm.split.hdu.edu.cn/showproblem.php?pid=5862 D ...

  4. Hdu 5862 Counting Intersections(有n条线段,每一条线段都是平行于x轴或者y轴,问有多少个交点+树状数组区间求和单点跟新)

    传送门:Hdu 5862 Counting Intersections 题意:有n条线段,每一条线段都是平行于x轴或者y轴,问有多少个交点 分析: 基本的操作流程是:先将所有的线段按照横树坐标x按小的 ...

  5. hdu 5862 Counting Intersections

    传送门:hdu 5862 Counting Intersections 题意:对于平行于坐标轴的n条线段,求两两相交的线段对有多少个,包括十,T型 官方题解:由于数据限制,只有竖向与横向的线段才会产生 ...

  6. HDU 5862 Counting Intersections 扫描线+树状数组

    题目链接: http://acm.split.hdu.edu.cn/showproblem.php?pid=5862 Counting Intersections Time Limit: 12000/ ...

  7. HDU 5862 Counting Intersections(离散化 + 树状数组)

    Counting Intersections Time Limit: 12000/6000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/ ...

  8. HDU 5862 Counting Intersections (离散化+扫描线+树状数组)

    题意:给你若干个平行于坐标轴的,长度大于0的线段,且任意两个线段没有公共点,不会重合覆盖.问有多少个交点. 析:题意很明确,可是并不好做,可以先把平行与x轴和y轴的分开,然后把平行y轴的按y坐标从小到 ...

  9. HDU 3333 | Codeforces 703D 树状数组、离散化

    HDU 3333:http://acm.hdu.edu.cn/showproblem.php?pid=3333 这两个题是类似的,都是离线处理查询,对每次查询的区间的右端点进行排序.这里我们需要离散化 ...

随机推荐

  1. iOS富文本(三)深入使用Text Kit

    在上一篇中介绍了Text Kit的三种基本组件的关系并且简单的实现了怎么使用这三种基本组件,本片将深入的去使用这三种基本组件. NSTextStorage NSTextStorage是NSMutabl ...

  2. HDU 3863 (博弈) No Gambling

    这是我见过的最简单的一道博弈了,其实不要被复杂的棋盘吓到了. 首先肯定会有而且仅有一个人胜,而且因为棋盘是对称的,所以先手相对于后手肯定更有优势,那么肯定是先手赢. 这是不是严格的推理,但是确实比较容 ...

  3. POJ2886 Who Gets the Most Candies? 线段树 反素数

    题意:有一群小朋友围成一个环,编号1,2,3…N.每个人手上握着一个非0的数字,首先第K个人出列,然后看他手上的数字,假设为m,则从下一个开始第m个人出列,一直如此.并设i为小于等于N的最大反素数,问 ...

  4. 浅谈 Scala 中下划线的用途

    Scala 作为一门函数式编程语言,对习惯了指令式编程语言的同学来说,会不大习惯,这里除了思维方式之外,还有语法层面的,比如 underscore(下划线)就会出现在多种场合,令初学者相当疑惑,今天就 ...

  5. Replication in Kafka

    Replication简介 Kafka中的Replication功能是为了给每个partition提供备份,当某个Broker挂掉时可以迅速实现故障切换(failover).我们可以在创建或修改top ...

  6. python练习程序(c100经典例15)

    题目: 利用条件运算符的嵌套来完成此题:学习成绩〉=90分的同学用A表示,60-89分之间的用B表示,60分以下的用C表示. def foo(n): if n>=90: print 'A' , ...

  7. python练习程序(c100经典例14)

    题目: 将一个正整数分解质因数.例如:输入90,打印出90=2*3*3*5. def foo(n): while 1: for i in range(2,n+1): if n%i==0: print ...

  8. jQuery事件绑定方式(转)

    bind() 简要描述 bind()向匹配元素添加一个或多个事件处理器. 使用方式 $(selector).bind(event,data,function) event:必需项:添加到元素的一个或多 ...

  9. mysql 表日常变化前几

    mysql 表日常变化前几use performance_schema create table test.snap1 as SELECT OBJECT_SCHEMA, OBJECT_NAME, CO ...

  10. SSH框架面试题

    Hibernate工作原理及为什么要用? 原理: 1. 读取并解析配置文件 2. 读取并解析映射信息,创建SessionFactory 3. 打开Sesssion 4. 创建事务Transation ...