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
", 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 }
原文地址:https://www.cnblogs.com/GBRgbr/p/3233497.html