HDU 4638 Group 树状数组 + 思路

实际上就是问这个区间编号连续的段的个数,假如一个编号连续的段有(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\n", 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 }

 

你可能感兴趣的:(group)