题意

有一群从 编号的防御塔,每个防御塔会有一个护盾,防御力是 。每一次,敌人会从 的他进行 的打击。这时候会将 小于等于0,就是这次护盾破了,之后收到的伤害会加倍,在此之前,受到的伤害是一倍。

你需要支持单点查询这个点收到的伤害。并支持区间打击。

树状数组-离线

考虑对于打击差分,由编号求解,对于时间建立树状数组。将打击和询问对于编号排序,我们每次只要处理出来一个编号的点所有的答案即可。

就是说,每次的打击如果是 ,此时时刻是 ,那么,就在 的树状数组上记一下,在做到编号是 的时候加 ,在做到 的时候减

比如下边这个样例:

5 8
1 2 3 4 5
A 1 3 2
A 1 4 1
Q 2
A 1 4 1
Q 1
A 1 4 1
Q 2
Q 4

图片说明

正如上图所示,我们差分之后做一个前缀和,就可以得到每个时刻每个点的值。不难二分出来打破盾的位置,以计算答案。

这种做法的时间复杂度是 ,但是实际上跑不到,所以和后边的 速度相差不远。

示例代码

#include <bits/stdc++.h>
using std::cin;
using std::cout;
using std::pair;
using std::make_pair;
#define For( i, j, k ) for( int i = j; i <= k; ++i )
#ifdef ONLINE_JUDGE
const int N = 210000, mod = 1e9 + 9;
#else
const int N = 100, mod = 1e9 + 9;
#endif
char ch; 
int n, q, a[ N ], tot, num;
pair < int, pair < int, int > > p[ N * 2 ];
pair < int, int > Q[ N ];
long long Sc[ N ], ans[ N ];
long long sum( int x )
{
 long long res = 0;
 while( x )
  res += Sc[ x ],
  x -= x & -x;
 return res;
}
void Add( int x, int d )
{
 while( x <= q )
 {
  Sc[ x ] += d;
  x += x & -x;
 }
 return;
}
void Solve( )
{
 int cur1 = 1, cur2 = 1;
 For( i, 1, n )
 {
  while( p[ cur1 ].first == i && cur1 <= tot )
   Add( p[ cur1 ].second.first, p[ cur1 ].second.second ), ++cur1;
  while( Q[ cur2 ].first == i && cur2 <= num )
  {
   int L = 1, R = Q[ cur2 ].second, IO = Q[ cur2 ].second;
   long long S;
   while( L <= R )
   {
    int mid = L + R >> 1;
    if( sum( mid ) >= a[ i ] )
     IO = mid, R = mid - 1;
    else
     L = mid + 1;
   }
   S = sum( IO );
   ans[ Q[ cur2 ].second ] = S + ( sum( Q[ cur2 ].second ) - sum( IO ) ) * 2;
   ++cur2;
  }
 }
 return;
}
int main( )
{
 std::ios::sync_with_stdio( false );
 cin.tie( 0 );
 cout.tie( 0 );
 cin >> n >> q;
 For( i, 1, n )
  cin >> a[ i ];
 int l, r, c;
 For( i, 1, q )
 {
  cin >> ch;
  if( ch == 'Q' )
   cin >> l,
   Q[ ++num ] = make_pair( l, i );
  else
   cin >> l >> r >> c,
   p[ ++tot ] = make_pair( l, make_pair( i, c ) ),
   p[ ++tot ] = make_pair( r + 1, make_pair( i, -c ) );
 }
 std::sort( p + 1, p + tot + 1 );
 std::sort( Q + 1, Q + num + 1 );
 memset( ans, -1, sizeof ans );
 Solve( );
 long long ANS = 0;
 For( i, 1, q ) if( ~ans[ i ] )
  ANS = ( ans[ i ] + ANS ) % mod;
 cout << ANS;
 return 0;
}

线段树-可在线

势能线段树

#include <bits/stdc++.h>
#define For( i, j, k ) for( int i = j; i <= k; ++i )
#define Rep( i, j, k ) for( int i = j; i >= k; --i )
using std::cin;
using std::cout;
inline int ls( int k ) { return k << 1; }
inline int rs( int k ) { return k << 1 | 1; }
const int N = 1e5 + 1, MOD = 1e9 + 9;
const long long INF = 0x3f3f3f3f3f3f3f3f;
int n, q, a[ N ];
long long ANS;
char ch;
struct Node
{
 int l, r;
 long long mn, tag;
}elvahs[ N * 4 ];
#define l( i ) elvahs[ i ].l
#define r( i ) elvahs[ i ].r
#define mn( i ) elvahs[ i ].mn
#define tag( i ) elvahs[ i ].tag
inline void Up( int k ) { mn( k ) = std::min( mn( ls( k ) ), mn( rs( k ) ) ); }
inline void PutTag( int k, long long x ) { mn( k ) -= x; tag( k ) += x; }
inline void Down( int k ) { if( tag( k ) ) PutTag( ls( k ), tag( k ) ), PutTag( rs( k ), tag( k ) ), tag( k ) = 0; }
void Build( int k, int l, int r )
{
 l( k ) = l, r( k ) = r;
 if( l == r )
 {
  mn( k ) = a[ l ];
  return;
 }
 int mid = l + r >> 1;
 return Build( ls( k ), l, mid ), Build( rs( k ), mid + 1, r ), Up( k );
}
void Modify( int k, int l, int r, int d )
{
 if( l <= l( k ) && r( k ) <= r && mn( k ) > d )
  return PutTag( k, d );
 if( l( k ) == r( k ) )
 {
  a[ l( k ) ] += d - mn( k );
  mn( k ) = INF;
  return;
 }
 Down( k );
 int mid = l( k ) + r( k ) >> 1;
 if( l <= mid )
  Modify( ls( k ), l, r, d );
 if( mid < r )
  Modify( rs( k ), l, r, d );
 return Up( k );
}
long long Query( int k, int pos )
{
 if( l( k ) == r( k ) )
  return ( mn( k ) <= a[ pos ] ) ? ( a[ pos ] - mn( k ) ) : ( a[ pos ] + ( INF - mn( k ) ) * 2 );
 Down( k );
 int mid = l( k ) + r( k ) >> 1;
 return pos <= mid ? Query( ls( k ), pos ) : Query( rs( k ), pos );
}
#undef l
#undef r
#undef mn
#undef tag
int main( )
{
 std::ios::sync_with_stdio( false );
 cin.tie( 0 );
 cout.tie( 0 );
 cin >> n >> q;
 For( i, 1, n )
  cin >> a[ i ];
 Build( 1, 1, n );
 int l, r, d;
 while( q-- )
 {
  cin >> ch >> l;
  if( ch == 'Q' )
   ANS += Query( 1, l );
  else
   cin >> r >> d, Modify( 1, l, r, d );
 }
 cout << ANS % MOD;
 return 0;
}