poj 1436 && zoj 1391 Horizontally Visible Segments (Segment Tree)

ZOJ :: Problems :: Show Problem

1436 -- Horizontally Visible Segments

  用线段树记录表面能被看见的线段的编号,然后覆盖的时候同时把能看到的线段记录下来。这里要用到拆点,在两个整点之间插入一个点。

  最后O(n^2)统计三角形的个数,因为每条线段可以看见的另外的线段的条数不多,所以可以直接枚举两条边。

代码如下:

 1 #include <cstdio>
 2 #include <iostream>
 3 #include <algorithm>
 4 #include <cstring>
 5 #include <set>
 6 
 7 using namespace std;
 8 
 9 const int N = 16666;
10 #define lson l, m, rt << 1
11 #define rson m + 1, r, rt << 1 | 1
12 #define root 0, 16000, 1
13 int cov[N << 2];
14 
15 void up(int rt) {
16     if (~cov[rt << 1] && cov[rt << 1] == cov[rt << 1 | 1]) cov[rt] = cov[rt << 1];
17     else cov[rt] = -1;
18 }
19 
20 void down(int rt) { if (~cov[rt]) cov[rt << 1] = cov[rt << 1 | 1] = cov[rt];}
21 
22 void build(int L, int R, int l, int r, int rt) {
23     if (l >= r) {
24         cov[rt] = L <= l && r <= R ? 1 : 0;
25         return ;
26     }
27     int m = l + r >> 1;
28     build(L, R, lson);
29     build(L, R, rson);
30     up(rt);
31 }
32 
33 set<int> edge[N >> 1];
34 
35 void update(int k, int L, int R, int l, int r, int rt) {
36     if (L <= l && r <= R && ~cov[rt]) {
37         if (cov[rt]) edge[k].insert(cov[rt]);
38         cov[rt] = k;
39         return ;
40     }
41     int m = l + r >> 1;
42     down(rt);
43     if (L <= m) update(k, L, R, lson);
44     if (m < R) update(k, L, R, rson);
45     up(rt);
46 }
47 
48 struct Node {
49     int l, r, p;
50 } seg[N >> 1];
51 
52 bool cmp(Node a, Node b) { return a.p < b.p;}
53 
54 int main() {
55 //    freopen("in", "r", stdin);
56     int T, n;
57     scanf("%d", &T);
58     while (T-- && ~scanf("%d", &n)) {
59         for (int i = 1; i <= n; i++) {
60             scanf("%d%d%d", &seg[i].l, &seg[i].r, &seg[i].p);
61             seg[i].l <<= 1, seg[i].r <<= 1;
62         }
63         sort(seg + 1, seg + n + 1, cmp);
64         edge[1].clear();
65         build(seg[1].l, seg[1].r, root);
66         for (int i = 2; i <= n; i++) {
67             edge[i].clear();
68             update(i, seg[i].l, seg[i].r, root);
69         }
70         set<int>::iterator si, sj;
71         int ans = 0;
72         for (int i = 1; i <= n; i++) {
73 //            cout << i << " : ";
74 //            for (si = edge[i].begin(); si != edge[i].end(); si++) cout << *si << ' ';
75 //            cout << endl;
76             for (si = edge[i].begin(); si != edge[i].end(); si++) {
77                 int t = *si;
78                 for (sj = edge[i].begin(); sj != edge[i].end(); sj++) {
79                     ans += edge[t].find(*sj) != edge[t].end();
80                 }
81             }
82         }
83         printf("%d\n", ans);
84     }
85     return 0;
86 }
View Code

 

 

——written by Lyon

 

转载于:https://www.cnblogs.com/LyonLys/p/poj_1436_zoj_1391_Lyon.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值