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 }

 

你可能感兴趣的:(visible)