HDU 4638 Group (线段树 + 离线)
题意:给定一个N长的序列,有n个人编号1-n , 第i个人和第i-1,i+1 互相为朋友,询问多次,问你询问的区间里面有多少堆(可以互相认识)朋友:
解题思路:开始一想有点像并查集的味道,不过想到LSS(我的队友,图论大牛)博客里面说的是线段树加离线(http://blog.csdn.net/u010126535),就按这个方面去想了,这题的主要思想是对询问的左端点按从大到小排序,然后对序列从后往前扫,对于A[I] 如果 A[I]- 1 或A[I] +1 出现过的话,更新其(它的两个邻居位置)线段树节点(+1);然后询问的答案就是这个区间长度-区间和,(这里主要是因为总是有一个连续序列排在最后面那个单独出来,我们就是求这个单独出来的个数,读者好好想想,我也是YY了好久。。)。
解题代码:
1 #include <stdio.h> 2 #include <string.h> 3 #include <iostream> 4 #include <algorithm> 5 #include <string> 6 #include <math.h> 7 8 using namespace std; 9 10 #define maxn 100005 11 struct op 12 { 13 int l , r ; 14 int num; 15 }ops[maxn]; 16 int hs[maxn]; 17 struct node 18 { 19 int l , r, m ; 20 int num ; 21 }tree[maxn*4]; 22 int L(int c) 23 { 24 return 2*c; 25 } 26 int R(int c) 27 { 28 return 2*c + 1; 29 } 30 void Pushup(int c) 31 { 32 tree[c].num = tree[L(c)].num + tree[R(c)].num; 33 } 34 void build(int c , int p , int v) 35 { 36 tree[c].l = p; 37 tree[c].r = v ; 38 tree[c].m = (p+v)/2; 39 tree[c].num = 0 ; 40 if(p == v) 41 return ; 42 build(L(c),p,tree[c].m); 43 build(R(c),tree[c].m+1,v); 44 } 45 void update(int c ,int p ) 46 { 47 if(tree[c].l == tree[c].r && tree[c].l == p) 48 { 49 tree[c].num ++ ; 50 return ; 51 } 52 if(p <= tree[c].m) update(L(c),p); 53 else if(p > tree[c].m) update(R(c),p); 54 Pushup(c); 55 } 56 int tsum = 0 ; 57 void getsum(int c , int p ,int v ) 58 { 59 if(p <= tree[c].l && v >= tree[c].r) 60 { 61 tsum += tree[c].num ; 62 return ; 63 } 64 if(v <= tree[c].m) getsum(L(c),p,v); 65 else if(p > tree[c].m) getsum(R(c),p,v); 66 else { 67 getsum(L(c),p,tree[c].m); 68 getsum(R(c),tree[c].m+1 ,v); 69 } 70 } 71 int a[maxn]; 72 int cmp(struct op a ,struct op b) 73 { 74 return a.l > b.l; 75 } 76 int ans[maxn]; 77 int main() 78 { 79 int t; 80 scanf("%d",&t); 81 while(t--) 82 { 83 memset(hs,0,sizeof(hs)); 84 int n ,m ; 85 scanf("%d %d",&n,&m); 86 build(1,1,n); 87 for(int i = 1;i <= n;i ++) 88 scanf("%d",&a[i]); 89 for(int i = 1;i <= m;i ++ ) 90 { 91 scanf("%d %d",&ops[i].l,&ops[i].r); 92 ops[i].num = i ; 93 } 94 sort(ops+1,ops+1+m,cmp); 95 int k = 1 ; 96 for(int i = n; i >= 1 ;i --) 97 { 98 hs[a[i]] = i ; 99 if(hs[a[i]-1] != 0 ) 100 { 101 update(1,hs[a[i]-1]); 102 } 103 if(hs[a[i]+1] != 0 ) 104 { 105 update(1,hs[a[i]+1]); 106 } 107 108 109 while(ops[k].l == i) 110 { 111 tsum = 0; 112 getsum(1,ops[k].l,ops[k].r); 113 ans[ops[k].num] =(ops[k].r - ops[k].l +1) -tsum; 114 k++; 115 } 116 } 117 for(int i= 1;i <= m;i ++) 118 printf("%d ",ans[i]); 119 } 120 121 return 0 ; 122 }