hdu 4638 Group

链接:http://acm.hdu.edu.cn/showproblem.php?pid=4638

大意:询问区间内有多少段连续的数,如3 1 2 5 4,区间[2,4]内有2段数,1~2和5

解法:考察当前插入一个数x会发生什么变化:如果x+1和x-1都已出现,那么x的插入会使得他们3个数连成一段,段的个数减少1;如果两者均没有出现,那么段的个数增加1;如果只出现其一,则段的个数不发生变化;那么,我们可以先将所有的数,按照这样的规律所取得的值插入到一颗线段树中,整个区间段的个数即为区间和;但是,询问不一定是整个区间,所以还需要删除前面的一些数,进一步,我们将所有询问读入后,按照左端点排序,对于每一个询问,删除左边的数,使得区间的左端点和询问区间的左端点相等;删除数会产生一些变化,例如3 1 2 5 4,一开始其值为1 1 -1 1 -1,删除3后,会对2,4的值产生影响,需要加一,表示段数增加,变为1 0 1 0,所以删除数x的时候,需要对x+1和x-1的值做加1的更新;每一个询问的答案就是query(q.x, q.y, 1, n, 1)

代码如下:

 1 #include <iostream>
 2 #include <cstdio>
 3 #include <cstring>
 4 #include <algorithm>
 5 #define lson l, m, rt<<1
 6 #define rson m+1, r, rt<<1|1
 7 using namespace std;
 8 
 9 const int M = 111111;
10 int n, m, sum[M<<2], ans[M], pos[M], a[M], id[M];
11 bool use[M];
12 
13 void pushup(int rt) { sum[rt] = sum[rt<<1] + sum[rt<<1|1]; }
14 
15 void update(int p, int x, int l, int r, int rt)
16 {
17     if (l == r) { sum[rt] += x; return ; }
18     int m = (l+r)/2;
19     if (p <= m) update(p, x, lson);
20     else update(p, x, rson);
21     pushup(rt);
22 }
23 
24 int query(int L, int R, int l, int r, int rt)
25 {
26     if (L <= l && r <= R) return sum[rt];
27     int m = (l+r)/2, ret = 0;
28     if (L <= m) ret += query(L, R, lson);
29     if (R > m) ret += query(L, R, rson);
30     return ret;
31 }
32 
33 struct Q
34 {
35     int x, y;
36 };
37 Q q[M];
38 
39 int cmp(const int i, const int j) { return q[i].x < q[j].x; }
40 
41 int main()
42 {
43     int T; scanf("%d", &T);
44     while ( T -- )
45     {
46         int n, m; scanf("%d%d", &n, &m);
47         for (int i=1; i<=n; i++)
48         {
49             scanf("%d", &a[i]);
50             pos[a[i]] = i;
51         }
52         memset(sum, 0, sizeof(sum));
53         memset(use, 0, sizeof(use));
54         for (int i=1; i<=n; i++)
55         {
56             if (use[a[i]-1] && use[a[i]+1]) update(i, -1, 1, n, 1);
57             else if (!use[a[i]-1] && !use[a[i]+1]) update(i, 1, 1, n, 1);
58             use[a[i]] = 1;
59         }
60         for (int i=0; i<m; i++) 
61         {
62             scanf("%d%d", &q[i].x, &q[i].y);
63             id[i] = i;
64         }
65         sort(id, id+m, cmp);
66         int s = 1;
67         for (int i=0; i<m; i++)
68         {
69             int k = id[i];
70             while (s <= n && q[k].x > s) //删除左边的数,使得区间的左端点与询问区间左端点一致 
71             {
72                 if (pos[a[s]+1] > s) update(pos[a[s]+1], 1, 1, n, 1);
73                 if (pos[a[s]-1] > s) update(pos[a[s]-1], 1, 1, n, 1);
74                 s ++;
75             }
76             ans[k] = query(q[k].x, q[k].y, 1, n, 1);
77         }
78         for (int i=0; i<m; i++) printf("%d\n", ans[i]);
79     }
80     //system("pause");
81     return 0;
82 }
View Code

 

posted @ 2013-08-02 18:07  sxqqslf  阅读(258)  评论(0编辑  收藏  举报