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)
代码如下:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
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 }