一道有意思的题目。
首先注意到这些操作都不是区间修改,所以可以用全局的东西来做。考虑每一次排序之后,可能会有一些加入操作以及异或操作,然后整个序列就是一些之前排好了序的,一些之后加入的。我们考虑维护之前排好序的,用一个trie就行了,维护之后加入的,直接一个数组就好了。然后考虑操作:加入操作不会影响trie,直接在数组中加入就好了。异或操作,不会改变数组的顺序,打一个标记。排序的话,我们先把所有没加入的数都加进去,然后考虑标记就行了。
这样讲可能有些难以讲懂,稍微解释一下。
如果没有push_back 操作,只有全局排序以及全局异或该怎么做?
我们可以记录一个trie,然后记录一下全局异或了多少,比如是allxor,然后我们询问的实际上就是当前第几大的数之类东西。那么考虑如何求这个东西,我们还是像一般的trie二分那样,但是因为有了全局异或的标记,所以比如现在到了第i位,如果allxor第i位是0,那么没有影响,否则0变成1,1变成0。
如果有了push_back操作,那么直接暴力记录一下就好了。
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 2e5 + 10;
int ls[N*30] , rs[N*30] , val[N*30][30] , sum[N*30];
int len , tcnt , nlen , txor , allxor , root;
int pre[N][30] , a[N];
void modify(int &o,int l,int r,int val)
{
if (!o) o = ++tcnt;
sum[o]++;
for (int i = 0;i < 30;i ++) if (val & (1 << i) ) ::val[o][i]++;
if (l == r) return;
int mid = l + r >> 1;
if (val <= mid) modify(ls[o] , l , mid , val);
else modify(rs[o] , mid + 1, r , val);
}
ll query(int o,int l,int r,int rnk,int dep = 29)
{
if (!o || !rnk) return 0;
if (l == r) return 1ll * (l ^ allxor) * rnk;
int mid = l + r >> 1;
if ( txor & (1 << dep) )
{
if (rnk <= sum[ rs[o] ] ) return query(rs[o] , mid + 1 , r , rnk , dep - 1);
ll ans = 0;
for (int i = 0;i < 30;i++)
{
if ( allxor & (1 << i) )
{
ans += ( 1ll * ( sum[ rs[o] ] - val[ rs[o] ][i] ) ) << i;
}else
{
ans += ( 1ll * val[rs[o]][i] ) << i;
}
}
return ans + query( ls[o] , l , mid , rnk - sum[rs[o]] , dep - 1);
}else
{
if (rnk <= sum[ ls[o] ] ) return query(ls[o] , l , mid , rnk , dep - 1);
ll ans = 0;
for (int i = 0;i < 30;i++)
{
if ( allxor & (1 << i) )
{
ans += ( 1ll * (sum[ ls[o] ] - val[ ls[o] ][i] ) ) << i;
}else
{
ans += ( 1ll * val[ls[o]][i] )<< i;
}
}
return ans + query( rs[o] , mid + 1, r , rnk - sum[ls[o]] , dep - 1);
}
}
ll query(int l,int r)
{
ll ans = 0;
if (r > nlen)
{
for (int i = 0;i < 30;i++)
{
int cal = pre[r][i] - pre[ max( nlen , l - 1 ) ][i] ;
if ( allxor & (1 << i) )
{
ans += 1ll * (r - max(l - 1 , nlen ) - cal) << i;
}else
{
ans += ( 1ll * cal )<< i;
}
}
}
if (l <= nlen) ans += query(root , 0 , ( 1 << 30 )- 1, min(r , nlen ) ) - query(root , 0 ,( 1 << 30 ) - 1, l - 1);
return ans;
}
int n , m;
int main()
{
scanf("%d",&n);
for (int i = 1;i <= n;i++)
{
scanf("%d",&a[++len]);
for (int j = 0;j < 30;j ++) pre[len][j] = pre[len - 1][j] + ( ( a[len] & (1 << j) ) ? 1 : 0 );
}
scanf("%d",&m);
while (m--)
{
int typ;scanf("%d",&typ);
if (typ == 1)
{
scanf("%d",&a[++len]);
a[len] ^= allxor;
for (int j = 0;j < 30;j ++) pre[len][j] = pre[len - 1][j] + ( ( a[len] & (1 << j) ) ? 1 : 0 );
}else
if (typ == 2)
{
int l ,r;scanf("%d%d",&l,&r);
printf("%lld\n",query(l , r) );
}else
if (typ == 3)
{
int x;scanf("%d",&x);
allxor ^= x;
}else
{
for (int i = nlen + 1;i <= len ;i++) modify(root , 0 , ( 1 << 30 ) - 1 , a[i] );
txor = allxor;nlen = len;
}
}
return 0;
}