hdu 5195 线段树

题目描述:给定一个DAG,求出允许移除最多K条边后的字典序最大的拓扑序列。

思路:线段树,每次找入度不超过K的最大编号的顶点,将此顶点从图中移除,重复操作n次即可得到结果。

吐槽:当时打BC的时候写出了一个直接贪心+拓扑排序的复杂度为O(n)的错误代码(当时还没有意识到是错误代码),交到hdu oj上居然给过了,后来上西方文化的时候和csc得瑟,说那个题我300+ms就给过了,在best solutions里面Rank 1,复杂度还是O(n)的,然后和csc说了我的想法以后才发现这思路TM根本就不对啊,航电的数据有点水吧!后来才改用线段树!

附超快-错误-可AC代码入下:

 1 #include <algorithm>

 2 #include <iostream>

 3 #include <cstring>

 4 #include <cstdio>

 5 #include <queue>

 6 using namespace std;

 7 

 8 priority_queue<int> q;

 9 const int N = 111111;

10 bool mark[N];

11 int in[N];

12 int head[N];

13 int ans[N], index;

14 int n, m, k, e;

15 

16 struct Edge

17 {

18     int v, next;

19 } edge[N];

20 

21 void addEdge( int u, int v )

22 {

23     edge[e].v = v;

24     edge[e].next = head[u];

25     head[u] = e;

26     e++;

27 }

28 

29 void init()

30 {

31     e = 0;

32     index = 0;

33     memset( in, 0, sizeof(in) );

34     memset( head, -1, sizeof(head) );

35     memset( mark, false, sizeof(mark) );

36     while ( !q.empty() )

37     {

38         q.pop();

39     }

40 }

41 

42 int main ()

43 {

44     while ( scanf("%d%d%d", &n, &m, &k) != EOF )

45     {

46         init();

47         for ( int i = 1; i <= m; i++ )

48         {

49             int u, v;

50             scanf("%d%d", &u, &v);

51             in[v]++;

52             addEdge( u, v );

53         }

54         for ( int i = n; i > 0 && k > 0; i-- )

55         {

56             if ( k >= in[i] )

57             {

58                 k -= in[i];

59                 in[i] = 0;

60                 ans[index++] = i;

61                 for ( int u = head[i]; u != -1; u = edge[u].next )

62                 {

63                     int v = edge[u].v;

64                     in[v]--;

65                 }

66                 mark[i] = true;                

67             }

68         }

69         for ( int i = 1; i <= n; i++ )

70         {

71             if ( in[i] == 0 && mark[i] == false )

72             {

73                 q.push(i);

74             }

75         }        

76         while ( !q.empty() )

77         {

78             int tmp = q.top();

79             q.pop();

80             ans[index++] = tmp;

81             for ( int u = head[tmp]; u != -1; u = edge[u].next )

82             {

83                 int v = edge[u].v;

84                 in[v]--;

85                 if ( in[v] == 0 )

86                 {

87                     q.push(v);

88                 }

89             }

90         }

91         for ( int i = 0; i < index - 1; i++ )

92         {

93             printf("%d ", ans[i]);

94         }

95         printf("%d\n", ans[index - 1]);

96     }

97     return 0;

98 }
View Code

附正确线段树代码如下:

  1 #include <iostream>

  2 #include <cstring>

  3 #include <cstdio>

  4 using namespace std;

  5 

  6 const int N = 100001;

  7 const int INF = 9999999;

  8 int in[N];

  9 int head[N];

 10 int n, m, k, e;

 11 

 12 int min( int a, int b )

 13 {

 14     return a < b ? a : b;

 15 }

 16 

 17 struct Edge 

 18 {

 19     int v, next;

 20 } edge[N];

 21 

 22 void addEdge( int u, int v )

 23 {

 24     edge[e].v = v;

 25     edge[e].next = head[u];

 26     head[u] = e++;

 27 }

 28 

 29 struct Node 

 30 {

 31     int l, r, in;

 32 } node[N * 3];

 33 

 34 void build( int i, int l, int r )

 35 {

 36     node[i].l = l, node[i].r = r;

 37     if ( l == r )

 38     {

 39         node[i].in = in[l];

 40         return ;

 41     }

 42     int mid = l + r >> 1;

 43     build( i << 1, l, mid );

 44     build( i << 1 | 1, mid + 1, r );

 45     node[i].in = min( node[i << 1].in, node[i << 1 | 1].in );    

 46     return ;

 47 }

 48 

 49 void update( int i, int pos )

 50 {

 51     if ( node[i].l == node[i].r )

 52     {

 53         node[i].in = in[pos];

 54         return ;

 55     }

 56     int mid = node[i].l + node[i].r >> 1;

 57     if ( pos <= mid )

 58     {

 59         update( i << 1, pos );

 60     }

 61     else

 62     {

 63         update( i << 1 | 1, pos );

 64     }

 65     node[i].in = min( node[i << 1].in, node[i << 1 | 1].in );

 66     return ;

 67 }

 68 

 69 int query( int i )

 70 {

 71     while ( node[i].l != node[i].r )

 72     {

 73         if ( k >= node[i << 1 | 1].in )

 74         {

 75             i = i << 1 | 1;

 76         }

 77         else

 78         {

 79             i = i << 1;

 80         }

 81     }

 82     return node[i].l;

 83 }

 84 

 85 void init()

 86 {

 87     e = 0;

 88     memset( head, -1, sizeof(head) );

 89     memset( in, 0, sizeof(in) );

 90 }

 91 

 92 int main ()

 93 {

 94     while ( scanf("%d%d%d", &n, &m, &k) != EOF )

 95     {

 96         init();

 97         while ( m-- )

 98         {

 99             int u, v;

100             scanf("%d%d", &u, &v);

101             addEdge( u, v );

102             in[v]++;

103         }

104         build( 1, 1, n );

105         for ( int i = 0; i < n - 1; i++ )

106         {

107             int t = query(1);

108             printf("%d", t);

109             if ( i < n - 1 ) putchar(' ');

110             k -= in[t];

111             in[t] = INF;

112             update( 1, t );

113             for ( int u = head[t]; u != -1; u = edge[u].next )

114             {

115                 int v = edge[u].v;

116                 if ( in[v] == INF ) continue;

117                 in[v]--;

118                 update( 1, v );

119             }

120         }

121         printf("%d\n", query(1));

122     }

123     return 0;

124 }

说明:用g++交不一定能过,最好挑个交题的人比较少的时候,c++妥妥的。

你可能感兴趣的:(HDU)