Problem
Description
Input
Output
Sample Input
6 6
8 9 1 13 9 3
1 4 5
2 6 9
1 3 7
2 7 7
1 6 1
2 11 13
Sample Output
45
19
21
Data Constraint
Solution
当x=0的时候,我们只要储存每一个位置上共有几个A[i]在此位上是1.然后每一个询问y,将他们拆开,如果第i位是1,
ans+=此位总共有1的A[i]的个数∗2i−1
继续。我们发现如果A[i]对答案有贡献(假设做到第j位),那么
2j≤A[i]Mod2j+1≤2j+1−1
.
所以,如果加上一个x,那么就要满足
2j≤A[i]Mod2j+1+x≤2j+1−1
,整理后,得
2j−x≤A[i]Mod2j+1≤2j+1−1−x
。
所以我们建很多个线段树组,第i个记录 A[i]Mod2i 的有多少个。
设 ll=2j−x,rr=2j+1−1−x
那么答案显然是 [ll,rr] 。
但有可能出现 2j−x<0 的情况。(即ll>rr)
ll=((−x+2j)Mod2j+1+2j+1])Mod2j+1
rr=((−x+2j+1−1)Mod2j+1+2j+1)Mod2j+1
Code
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#define N 1048580
#define NN 100010
#define LL long long
#define fo(i,a,b) for(i=a;i<=b;i++)
using namespace std;
LL ans,tree[21][N];
int _2[22],n,i,j,k,q,a[NN],opt,x,y;
int lowbit(int x){return x&(-x);}
void change(int p,int k,LL num)
{
k++;
while (k<=_2[p+1])
{
tree[p][k]+=num;
k+=lowbit(k);
}
}
LL find(int p,int k)
{
int sum=0;
k++;
while (k)
{
sum+=tree[p][k];
k-=lowbit(k);
}
return sum;
}
int main()
{
_2[0]=1;
fo(i,1,20) _2[i]=_2[i-1]*2;
scanf("%d%d",&n,&q);
fo(i,1,n) scanf("%d",&a[i]);
fo(i,1,n)
fo(j,0,19) change(j,a[i]%_2[j+1],1);
fo(i,1,q)
{
scanf("%d%d%d",&opt,&x,&y);
if (opt==1)
{
fo(j,0,19) change(j,a[x]%_2[j+1],-1);
fo(j,0,19) change(j,y%_2[j+1],1);
a[x]=y;
} else
{
ans=0;
int ll,rr;
fo(j,0,19)
{
if (_2[j]&y)
{
ll=((-x+_2[j])%_2[j+1]+_2[j+1])%_2[j+1];
rr=((-x+_2[j+1]-1)%_2[j+1]+_2[j+1])%_2[j+1];
if (ll<=rr)
{
ans+=_2[j]*find(j,rr);
ans-=_2[j]*find(j,ll-1);
} else
{
ans+=_2[j]*find(j,_2[j+1]-1);
ans-=_2[j]*find(j,ll-1);
ans+=_2[j]*find(j,rr);
}
}
}
printf("%lld\n",ans);
}
}
}
——2016.8.17