实际上就是问这个区间编号连续的段的个数,假如一个编号连续的段有(a+b)个人,我把他们分在同一组能得到的分值为(a+b)^2,而把他们分成人数为a和b的两组的话,得到的分值就是a^2+b^2,显然(a+b)^2 > a^2+b^2,所以对于每个区间,尽可能把他们分成尽量少的组。
考虑把这些数从后往前添加,每添加一个数num[i],如果num[i]+1或者num[i]-1有且只有一个已经存在,则段数不变;如果num[i]+1和num[i]-1同时存在,则段数-1,如果都不在,则段数+1。
对于每个数num[i],我们记录把它添加进去的时候,它对段数产生的影响为c[i]( 即插入num[i]时对区间[i, N]的段数产生的影响 ),查询就是求c[i]的区间和。
对于询问我们做离线处理,把每个询问按右端点从大到小排序,从后往前扫描,每次把询问右端点之外的数删掉,根据其是否会产生影响对c[i]进行更新。
Sum( Query[i].r ) - Sum( Query[i].l - 1 ) 即为答案。
1 #include <cstdio> 2 #include <cstring> 3 #include <cstdlib> 4 #include <algorithm> 5 6 using namespace std; 7 8 const int MAXN = 100010; 9 10 struct node 11 { 12 int l, r, id; 13 }; 14 15 int N, Q; 16 node qry[MAXN]; //查询 17 int C[MAXN]; //树状数组 18 int num[MAXN]; //原数组 19 int addr[MAXN]; //每个数在哪个位置 20 int ans[MAXN]; //记录答案 21 bool use[MAXN]; //该数是否存在 22 23 bool cmp( node a, node b ) 24 { 25 return a.r > b.r; 26 } 27 28 int lowbit( int x ) 29 { 30 return x & (-x); 31 } 32 33 int Query( int x ) 34 { 35 int res = 0; 36 while ( x > 0 ) 37 { 38 res += C[x]; 39 x -= lowbit(x); 40 } 41 return res; 42 } 43 44 void Update( int x, int val ) 45 { 46 while ( x <= N ) 47 { 48 C[x] += val; 49 x += lowbit(x); 50 } 51 return; 52 } 53 54 void init() 55 { 56 memset( C, 0, sizeof(C) ); 57 memset( use, false, sizeof(use) ); 58 59 for ( int i = N; i > 0; --i ) 60 { 61 if ( use[ num[i] - 1 ] && use[ num[i] + 1 ] ) 62 { 63 Update( i, -1 ); 64 } 65 else if ( !( use[ num[i] - 1 ] || use[ num[i] + 1 ] ) ) 66 { 67 Update( i, 1 ); 68 } 69 use[ num[i] ] = true; 70 } 71 return; 72 } 73 74 void solved() 75 { 76 int j = N; 77 for ( int i = 0; i < Q; ++i ) 78 { 79 while ( j > 0 && j > qry[i].r ) 80 { 81 if ( num[j] > 1 && addr[ num[j] - 1 ] < j ) 82 { 83 Update( addr[ num[j] - 1 ], 1 ); 84 } 85 if ( num[j] < N && addr[ num[j] + 1 ] < j ) 86 { 87 Update( addr[ num[j] + 1 ], 1 ); 88 } 89 --j; 90 } 91 ans[ qry[i].id ] = Query( qry[i].r ) - Query( qry[i].l - 1 ); 92 } 93 94 for ( int i = 0; i < Q; ++i ) 95 printf( "%d ", ans[i] ); 96 97 return; 98 } 99 100 int main() 101 { 102 int T; 103 scanf( "%d", &T ); 104 while ( T-- ) 105 { 106 scanf( "%d%d", &N, &Q ); 107 for ( int i = 1; i <= N; ++i ) 108 { 109 scanf( "%d", &num[i] ); 110 addr[ num[i] ] = i; 111 } 112 for ( int i = 0; i < Q; ++i ) 113 { 114 scanf("%d%d", &qry[i].l, &qry[i].r ); 115 qry[i].id = i; 116 } 117 sort( qry, qry + Q, cmp ); 118 119 init(); 120 solved(); 121 } 122 return 0; 123 }