题意
有一群从 至
编号的防御塔,每个防御塔会有一个护盾,防御力是
。每一次,敌人会从
到
的他进行
的打击。这时候会将
若
小于等于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;
} 
京公网安备 11010502036488号