标准解法应该是线段树,这里提供另一种思路:将“断点”(即被摧毁的村庄)放入stl的容器(我用的是set)中维护,对于每次查询,只要找这个数在哪两个断点之间即可,写起来轻松愉快。

PS:hdu上的数据略坑,同一个村庄可以被摧毁多次,恢复的时候一次恢复就可以让它不再是断点,但是第一次恢复以后剩下几次也是需要恢复的...所以不能把它被摧毁的记录删除,另外没有被摧毁的村庄时也有R操作。poj上的数据比较规范,符合实际情况,没有上面的奇怪数据。

 1 #include 
 2 #include 
 3 #include 
 4 #include 
 5 #include 
 6 #include <set>
 7 using namespace std;
 8 
 9 set<int> s;
10 set<int>::iterator it;
11 stack<int> st;
12 
13 int main ()
14 {
15     int n, m;
16     while ( scanf("%d%d", &n, &m) != EOF )
17     {
18         while ( !st.empty() ) st.pop();
19         s.clear();
20         char op[2];
21         int x;
22         while ( m-- )
23         {
24             scanf("%s", op);
25             if ( op[0] == 'D' )
26             {
27                 scanf("%d", &x);
28                 s.insert(x);
29                 st.push(x);
30             }
31             else if ( op[0] == 'Q' )
32             {
33                 scanf("%d", &x);
34                 if ( s.find(x) != s.end() )
35                 {
36                     printf("0\n");
37                 }
38                 else
39                 {
40                     int l = 1, r = n;
41                     it = s.upper_bound(x);
42                     if ( it != s.end() )
43                     {
44                         r = (*it) - 1;
45                     }
46                     if ( it != s.begin() )
47                     {
48                         it--;
49                         l = (*it) + 1;
50                     }
51                     printf("%d\n", r - l + 1);
52                 }
53             }
54             else
55             {
56                 if ( st.empty() ) continue;
57                 int tmp = st.top();
58                 st.pop();
59                 s.erase(tmp);
60             }
61         }
62     }
63     return 0;
64 }