单调栈+前缀和
max很明显用单调栈搞,但是异或和呢?异或和我们拆位,对于每段区间的异或和[l[i]-i],[i,r[i]]答案就是0->1,1->0的乘积,但是统计的时候事实上是[l[i]-2,i-1],因为异或和本身是前缀和,所以要-1,单调栈又是一个前缀和,也要-1,所以就是-2
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include<bits/stdc++.h> using namespace std; typedef long long ll; const int N = 1e5 + 5, mod = 1e9 + 61; int n; int l[N], r[N], st[N]; ll a[N], sum[N][31]; void up(ll &x, const ll &t) { x = ((x + t) % mod + mod) % mod; } int main() { int T; scanf("%d", &T); while(T--) { int top = 0; ll ans = 0, tot = 0; scanf("%d", &n); for(int i = 1; i <= n; ++i) { scanf("%lld", &a[i]); tot = tot ^ a[i]; for(int j = 0; j < 31; ++j) sum[i][j] = sum[i - 1][j] + ((tot & (1 << j)) > 0); } for(int i = 1; i <= n; ++i) { l[i] = r[i] = i; while(top && a[i] > a[st[top]]) { r[st[top - 1]] = r[st[top]]; l[i] = l[st[top]]; --top; } st[++top] = i; } while(top) r[st[top - 1]] = r[st[top]], --top; for(int i = 1; i <= n; ++i) { ll pw = 1; for(int j = 0; j < 30; ++j) { ll tmp1 = sum[r[i]][j] - sum[i - 1][j], tmp2 = sum[i - 1][j] - sum[max(l[i] - 2, 0)][j]; up(ans, tmp1 * (ll)(i - l[i] + 1 - tmp2) % mod * pw % mod * a[i] % mod); up(ans, (ll)(r[i] - i + 1 - tmp1) * tmp2 % mod * pw % mod * a[i] % mod); pw = pw * 2 % mod; } } printf("%lld ", ans); } return 0; }