F. Sonya and Bitwise OR
time limit per test
4 seconds
memory limit per test
512 megabytes
input
standard input
output
standard output
Sonya has an array a1,a2,…,ana1,a2,…,an consisting of nn integers and also one non-negative integer xx. She has to perform mm queries of two types:
- 11 ii yy: replace ii-th element by value yy, i.e. to perform an operation aiai := yy;
- 22 ll rr: find the number of pairs (LL, RR) that l≤L≤R≤rl≤L≤R≤r and bitwise OR of all integers in the range [L,R][L,R] is at least xx (note that xx is a constant for all queries).
Can you help Sonya perform all her queries?
Bitwise OR is a binary operation on a pair of non-negative integers. To calculate the bitwise OR of two numbers, you need to write both numbers in binary notation. The result is a number, in binary, which contains a one in each digit if there is a one in the binary notation of at least one of the two numbers. For example, 1010 OR 1919 = 1010210102 OR 100112100112 = 110112110112 = 2727.
Input
The first line contains three integers nn, mm, and xx (1≤n,m≤1051≤n,m≤105, 0≤x<2200≤x<220) — the number of numbers, the number of queries, and the constant for all queries.
The second line contains nn integers a1,a2,…,ana1,a2,…,an (0≤ai<2200≤ai<220) — numbers of the array.
The following mm lines each describe an query. A line has one of the following formats:
- 11 ii yy (1≤i≤n1≤i≤n, 0≤y<2200≤y<220), meaning that you have to replace aiai by yy;
- 22 ll rr (1≤l≤r≤n1≤l≤r≤n), meaning that you have to find the number of subarrays on the segment from ll to rr that the bitwise OR of all numbers there is at least xx.
Output
For each query of type 2, print the number of subarrays such that the bitwise OR of all the numbers in the range is at least xx.
Examples
input
Copy
4 8 7 0 3 6 1 2 1 4 2 3 4 1 1 7 2 1 4 2 1 3 2 1 1 1 3 0 2 1 4
output
Copy
5 1 7 4 1 4
input
Copy
5 5 7 6 0 3 15 2 2 1 5 1 4 4 2 1 5 2 3 5 2 1 4
output
Copy
9 7 2 4
Note
In the first example, there are an array [00, 33, 66, 11] and queries:
- on the segment [1…41…4], you can choose pairs (11, 33), (11, 44), (22, 33), (22, 44), and (33, 44);
- on the segment [3…43…4], you can choose pair (33, 44);
- the first number is being replacing by 77, after this operation, the array will consist of [77, 33, 66, 11];
- on the segment [1…41…4], you can choose pairs (11, 11), (11, 22), (11, 33), (11, 44), (22, 33), (22, 44), and (33, 44);
- on the segment [1…31…3], you can choose pairs (11, 11), (11, 22), (11, 33), and (22, 33);
- on the segment [1…11…1], you can choose pair (11, 11);
- the third number is being replacing by 00, after this operation, the array will consist of [77, 33, 00, 11];
- on the segment [1…41…4], you can choose pairs (11, 11), (11, 22), (11, 33), and (11, 44).
In the second example, there are an array [66, 00, 33, 1515, 22] are queries:
- on the segment [1…51…5], you can choose pairs (11, 33), (11, 44), (11, 55), (22, 44), (22, 55), (33, 44), (33, 55), (44, 44), and (44, 55);
- the fourth number is being replacing by 44, after this operation, the array will consist of [66, 00, 33, 44, 22];
- on the segment [1…51…5], you can choose pairs (11, 33), (11, 44), (11, 55), (22, 44), (22, 55), (33, 44), and (33, 55);
- on the segment [3…53…5], you can choose pairs (33, 44) and (33, 55);
- on the segment [1…41…4], you can choose pairs (11, 33), (11, 44), (22, 44), and (33, 44).
题意:给你N个数,M个询问,支持单点更新,区间查询,区间或和>=X的对数。
解题思路:线段树区间合并。由于是或,所以对于一个区间而言,他从前往后跟从后往前组成的数字不会很多。所以完全可以暴力的区间合并。对于线段树上的节点,维护当前ans,和前缀或的种类和数量,后缀或的种类和数量。然后合并的时候。
左节点的后缀 跟 右节点的前缀 ,暴力合并即可。
然后要更新当前节点的后缀和前缀。先让当前节点的后缀等于右节点的后缀,然后暴力左节点的所有后缀跟当前节点的后缀的最后一个的或,插入到当前节点中即可。根据或的性质,值只会越来越大,所以这么做是没问题的。
#include <bits/stdc++.h>
using namespace std;
typedef long long int ll;
const int MAXN = 100005;
const int INF = 0x3f3f3f3f;
typedef pair<int,int> pii;
int a[MAXN];
struct node{
ll sum;
vector<pii> suff;
vector<pii> pref;
node(){
sum=0;
}
}t[MAXN<<2];
int N,M,X;
//加了个引用,快了1s钟
ll getans(node &r1,node &r2){
ll ans=0;
//两个for暴力,完全没问题,因为数字种类不会很多
for(pii &i:r1.suff){
for(pii &j:r2.pref){
if((i.second|j.second)>=X)
ans+=ll(i.first)*ll(j.first);
}
}
return ans;
}
//加了个引用,快了1s钟
node pushup(node &r1,node &r2){
if(r1.pref.size()==0)
return r2;
if(r2.pref.size()==0)
return r1;
node ans;
ans.sum=r1.sum+r2.sum;
ans.sum+=getans(r1,r2);
//暴力更新当前节点后缀(从后往前读的那种后缀)
ans.suff=r2.suff;
for(pii &i:r1.suff)
{
pii b=r2.suff.back();
if((i.second|b.second)==ans.suff.back().second){
ans.suff.back().first+=i.first;
}
else{
ans.suff.push_back({i.first,i.second|b.second});
}
}
//暴力更新当前节点前缀
ans.pref=r1.pref;
for(pii &i:r2.pref)
{
pii b=r1.pref.back();
if((i.second|b.second)==ans.pref.back().second){
ans.pref.back().first+=i.first;
}
else{
ans.pref.push_back({i.first,i.second|b.second});
}
}
return ans;
}
void build(int l,int r,int rt){
if(l==r){
if(a[l]>=X)
t[rt].sum=1;
t[rt].pref.push_back({1,a[l]});
t[rt].suff.push_back({1,a[l]});
return;
}
int m=(l+r)/2;
build(l,m,rt<<1);
build(m+1,r,rt<<1|1);
t[rt]=pushup(t[rt<<1],t[rt<<1|1]);
}
void update(int L,int C,int l,int r,int rt){
if(l==r){
if(C>=X)
t[rt].sum=1;
else
t[rt].sum=0;
a[l]=C;
t[rt].pref.clear();
t[rt].suff.clear();
t[rt].pref.push_back({1,C});
t[rt].suff.push_back({1,C});
return;
}
int m=(l+r)/2;
if(L<=m)
update(L,C,l,m,rt<<1);
else
update(L,C,m+1,r,rt<<1|1);
t[rt]=pushup(t[rt<<1],t[rt<<1|1]);
}
node query(int L,int R,int l,int r,int rt){
if(L<=l&&r<=R)
return t[rt];
int m=(l+r)/2;
node ans;
if(L<=m){
node t=query(L,R,l,m,rt<<1);
ans=pushup(t,ans);
}
if(R>m){
node t=query(L,R,m+1,r,rt<<1|1);
ans=pushup(ans,t);//注意,查询的时候答案也要合并。
}
return ans;
}
int main()
{
scanf("%d%d%d",&N,&M,&X);
for(int i=1;i<=N;i++)
scanf("%d",&a[i]);
build(1,N,1);
int op,u,v;
while(M--){
scanf("%d%d%d",&op,&u,&v);
if(op==1)
update(u,v,1,N,1);
else{
printf("%lld\n",query(u,v,1,N,1).sum);
}
}
return 0;
}