ZOJ 1391 Horizontally Visible Segments

挺不错的一道线段树,薛神给的礼物,WA了整整一天才过,各种细节出错OTL……

1.纵坐标扩大两倍保存,不然样例都跑不过。即(0, 2)与(3, 4)之间可以有一条横线,但是如果坐标不扩大,这条横线是过不去的。

2.按x值从小到大排序,插入线段树,每次将Line[id]更新到线段树中之前,先查询编号为Line[id]向左可以看到哪几条线段(即可以看到哪几条编号比它小的线段),用vector保存,注意去重,不然最后结果会多。(vector忘了clear这里错了好几次。。。)

3.id[MAXN]用来标记该段最顶端的线段的编号,-1代表该段没被覆盖或者该段不是被同一条线段覆盖

4.四重循环暴力枚举,暂时也没想到别的好办法……或许是因为数据弱的缘故,交上去效率还可以,140ms AC。

 

  1 #include <cstdio>
  2 #include <cstring>
  3 #include <cstdlib>
  4 #include <vector>
  5 #include <algorithm>
  6 
  7 #define lson l, m, rt << 1
  8 #define rson m + 1, r, rt << 1 | 1
  9 
 10 using namespace std;
 11 
 12 const int MAXLEN = 8010 << 1;
 13 const int MAXN = 8010;
 14 
 15 struct MyLine
 16 {
 17     int y1, y2;
 18     int x;
 19 };
 20 
 21 int N, bound;
 22 vector<int> see[MAXN];
 23 MyLine L[MAXN];
 24 
 25 int  id[ MAXLEN << 2 ];
 26 
 27 bool cmp( MyLine a, MyLine b )
 28 {
 29     return a.x < b.x;
 30 }
 31 
 32 void PushUp( int rt )
 33 {
 34     int lc = rt << 1;
 35     int rc = rt << 1 | 1;
 36     if ( id[lc] == id[rc] )
 37         id[rt] = id[lc];
 38     else
 39         id[rt] = -1;
 40     return;
 41 }
 42 
 43 void PushDown( int rt )
 44 {
 45     int lc = rt << 1;
 46     int rc = rt << 1 | 1;
 47     if ( id[rt] != -1 )
 48         id[lc] = id[rc] = id[rt];
 49 
 50     return;
 51 }
 52 
 53 bool check( int c, int tar )   //去除重点
 54 {
 55     int len = see[c].size();
 56     for ( int i = 0; i < len; ++i )
 57         if ( tar == see[c][i] ) return false;
 58     return true;
 59 }
 60 
 61 void Query( int L, int R, int c, int l, int r, int rt )
 62 {
 63     if ( id[rt] != -1 )
 64     {
 65         if ( check( c, id[rt] ) ) see[c].push_back( id[rt] );
 66         return;
 67     }
 68     if ( l >= r ) return;
 69     PushDown(rt);
 70     int m = ( l + r ) >> 1;
 71     if ( L <= m ) Query( L, R, c, lson );
 72     if ( R > m ) Query( L, R, c, rson );
 73 
 74     PushUp(rt);
 75     return;
 76 }
 77 
 78 void Update( int L, int R, int c, int l, int r, int rt )
 79 {
 80     if ( L <= l && r <= R )
 81     {
 82         id[rt] = c;
 83         return;
 84     }
 85     PushDown(rt);
 86     int m = ( l + r ) >> 1;
 87     if ( L <= m ) Update( L, R, c, lson );
 88     if ( R > m ) Update( L, R, c, rson );
 89     PushUp( rt );
 90     return;
 91 }
 92 
 93 int main()
 94 {
 95     int T;
 96     // freopen( "in.txt", "r", stdin );
 97     scanf( "%d", &T );
 98     while ( T-- )
 99     {
100         scanf( "%d", &N );
101         bound = 0;
102 
103         memset( id, -1, sizeof(id) );
104         for ( int i = 0; i < N; ++i )
105         {
106             scanf("%d%d%d", &L[i].y1, &L[i].y2, &L[i].x );
107             L[i].y1 *= 2;
108             L[i].y2 *= 2;
109             see[i].clear();  // 勿忘清空
110             bound = max( bound, L[i].y2 );
111         }
112 
113         sort( L, L + N, cmp );
114 
115         for ( int i = 0; i < N; ++i )
116         {
117             Query( L[i].y1, L[i].y2, i, 0, bound, 1 );
118             Update( L[i].y1, L[i].y2, i, 0, bound, 1 );
119         }
120 
121         int ans = 0;
122         for ( int i = 0; i < N; ++i )
123         {
124             int sz = see[i].size();
125             for ( int j = 0; j < sz; ++j )
126             {
127                 int i2 = see[i][j];    //i can see i2
128                 int sz2 = see[i2].size();
129                 for ( int y = 0; y < sz2; ++y )  //i2 can see see[i2][y]
130                     for ( int x = 0; x < sz; ++x )
131                     {
132                         if ( x != j && see[i][x] == see[i2][y] )
133                             ++ans;
134                     }
135             }
136         }
137 
138         printf( "%d\n", ans );
139     }
140     return 0;
141 }

 

转载于:https://www.cnblogs.com/GBRgbr/archive/2013/05/14/3078268.html

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值