一组数据:
2
9 10 2
2 3 1 4 2 5 1 3 4
0 1 0 1 1 1 1 1 0
1
0 4
1
0 4
1
0 5
0 7
1
0 2
1
5 10 2
1 1 1 1 1
0 1 0 1 0
1
0 3
1
0 3
1
0 1
0 4
0 5
0 2
1
答案:
16
16
16
16
15
6
6
6
6
以第一组为例:
2 3 1 4 2 5 1 3 4
以小于K的数为分界,将数列分成几段。
对于每个数字,记录它所在段的左端点和右端点,据此求出修改前的合法对数sum。
对于每个修改,查看当前修改发生在哪一段,该修改对sum产生了怎样的影响,修改sum即可。
树状数组C[i]记录区间[1, i]共有多少个白点。
注意修改发生在段内和段端点处要分开考虑。
#include <cstdio> #include <cstring> #include <cstdlib> #include <algorithm> #define LL long long int using namespace std; const int MAXN = 100100; int N, Q, K; int C[MAXN]; //1-i之间有多少个白点 int val[MAXN]; int left[MAXN]; int right[MAXN]; LL sum; bool color[MAXN]; int lowbit( int x ) { return x & (-x); } void Update( int x, int val ) { while ( x <= N ) { C[x] += val; x += lowbit(x); } return; } int Query( int x ) { if ( x == 0 ) return 0; int res = 0; while ( x > 0 ) { res += C[x]; x -= lowbit(x); } return res; } void init() { int pre = 0; for ( int i = 1; i <= N; ++i ) { left[i] = pre; if ( val[i] < K ) pre = i; } pre = N + 1; for ( int i = N; i > 0; --i ) { if ( val[i] < K ) pre = i; right[i] = pre; } return; } int main() { //freopen( "in.txt", "r", stdin ); int T; scanf( "%d", &T ); while ( T-- ) { memset( C, 0, sizeof(C) ); scanf( "%d%d%d", &N, &Q, &K ); for ( int i = 1; i <= N; ++i ) scanf("%d", &val[i] ); for ( int i = 1; i <= N; ++i ) { int a; scanf("%d", &a ); if ( a == 0 ) { Update( i, 1 ); color[i] = true; } else color[i] = false; } init(); sum = 0; for ( int i = 1; i <= N; ++i ) if ( val[i] < K ) { LL white = Query(i) - Query( left[i] ); LL black = i - left[i] - white; LL houW = Query(N) - Query(i - 1); LL houB = N - i + 1 - houW; sum += white * houB + black * houW; } for ( int i = 0; i < Q; ++i ) { int op; scanf( "%d", &op ); if ( op == 0 ) { int v; scanf( "%d", &v ); LL preW, preB, aftW, aftB; if ( val[v] >= K ) { preW = Query( left[v] ); preB = left[v] - preW; aftW = Query(N) - Query( right[v] - 1 ); aftB = N - right[v] + 1 - aftW; } else { preW = Query( v - 1 ); preB = v - 1 - preW; aftW = Query(N) - Query(v); aftB = N - v - aftW; } if ( color[v] ) //之前是白的 { sum = sum - preB - aftB + preW + aftW; Update( v, -1 ); } else //之前是黑的 { sum = sum + preB + aftB - preW - aftW; Update( v, 1 ); } color[v] = !color[v]; } else printf( "%I64d ", sum ); } } return 0; }