題目
正解
首先考慮某個修改(設修改)對某次詢問(設修改)的影響。可以發現它的貢獻是區間交乘權值乘和相同二進制位上的的個數。
分塊是這種問題的常規套路。將數字分成的兩段。
先考慮單點修改的情況。
設表示修改時前綴爲,對詢問後綴爲的影響。
修改的時候,找到對應的,然後用的時間處理它對每個後綴的影響。
詢問的時候,用的時間枚舉,然後找到對應的,加起來。
這樣時間複雜度是的。
在考慮對區間的貢獻。將左端點和右端點拆開,那麼就相當於將某個位置後面的數區間加,或者詢問前綴和。
於是分治,處理時間發生在前對時間發生後、且操作位置在前對操作位置在後的影響。
每個記一個一次函數就可以了。
於是時間複雜度
代碼
這題有點卡常數,所以當cdq分治到長度比較小的時候就暴力。
代碼出現了莫名其妙的錯誤,如果只把暴力拿出來條發現這個錯誤還是存在的。目前沒有發現任何原因。如果有路過的大佬發現了請指正。
using namespace std;
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <cassert>
#define N 65536
#define _B 256
#define ll long long
#define mo 1000000007
int input(){
// int x;
// scanf("%d",&x);
// return x;
char ch=getchar();
while (ch<'0' || ch>'9')
ch=getchar();
int x=0;
do{
x=x*10+ch-'0';
ch=getchar();
}
while ('0'<=ch && ch<='9');
return x;
}
int n,m,B,bit;
int same0[_B][_B],same0_[_B][_B];
struct Oper{
int op,x,l,c;
int t;
} o[N*2+10],p[N*2+10];
bool cmpo(const Oper &a,const Oper &b){return a.l<b.l || a.l==b.l && a.op<b.op;}
ll a[N+10],b[N+10];
ll ans[N+10];
void cdq(int l,int r){
if (l>=r)
return;
if (r-l+1<=B){
for (int i=l;i<=r;++i)
if (o[i].op==0){
int prei=o[i].x>>bit,suci=o[i].x&B-1;
for (int j=i+1;j<=r;++j)
if (o[j].op==1 && o[j].l>=o[i].l){
int prej=o[j].x>>bit,sucj=o[j].x&B-1;
ll tmp=(ll)same0[prei][prej]*same0[suci][sucj]*((ll)o[i].c*o[j].c%mo)%mo;
(ans[o[j].t]+=(ll)(o[j].l-o[i].l+1)*tmp)%=mo;
}
}
sort(o+l,o+r+1,cmpo);
return;
}
int mid=l+r>>1;
cdq(l,mid),cdq(mid+1,r);
int i=l,j=mid+1,k=l;
while (i<=mid && j<=r)
if (o[i].l<=o[j].l){
if (o[i].op==0){
ll l=o[i].l,c=o[i].c,tmp=(ll)c*(1-l+mo)%mo;
int pre=o[i].x>>bit,suc=o[i].x&B-1;
for (register int t=0;t<B;++t)
(a[pre<<bit|t]+=(ll)c*same0[suc][t])%=mo;
for (register int t=0;t<B;++t)
(b[pre<<bit|t]+=(ll)tmp*same0[suc][t])%=mo;
}
p[k++]=o[i];
i++;
}
else{
if (o[j].op==1){
ll l=o[j].l,c=o[j].c;
int pre=o[j].x>>bit,suc=o[j].x&B-1;
if (c==1)
for (register int t=0;t<B;++t)
(ans[o[j].t]+=((ll)a[t<<bit|suc]*l+b[t<<bit|suc])%mo*same0[pre][t])%=mo;
else
for (register int t=0;t<B;++t)
(ans[o[j].t]+=((ll)a[t<<bit|suc]*l+b[t<<bit|suc])%mo*same0_[pre][t])%=mo;
}
p[k++]=o[j];
j++;
}
for (;j<=r;++j){
if (o[j].op==1){
ll l=o[j].l,c=o[j].c;
int pre=o[j].x>>bit,suc=o[j].x&B-1;
if (c==1)
for (register int t=0;t<B;++t)
(ans[o[j].t]+=((ll)a[t<<bit|suc]*l+b[t<<bit|suc])%mo*same0[pre][t])%=mo;
else
for (register int t=0;t<B;++t)
(ans[o[j].t]+=((ll)a[t<<bit|suc]*l+b[t<<bit|suc])%mo*same0_[pre][t])%=mo;
}
p[k++]=o[j];
}
for (int t=i;t<=mid;++t)
p[k++]=o[t];
for (--i;i>=l;--i)
if (o[i].op==0){
int pre=o[i].x>>bit;
memset(a+(pre<<bit),0,sizeof(ll)*B);
memset(b+(pre<<bit),0,sizeof(ll)*B);
// for (register int t=0;t<B;++t)
// a[pre<<bit|t]=b[pre<<bit|t]=0;
}
memcpy(o+l,p+l,sizeof(Oper)*(r-l+1));
}
int main(){
freopen("and.in","r",stdin);
freopen("and.out","w",stdout);
n=input(),m=input();
B=sqrt(n);
for (bit=0;1<<bit<B;++bit);
for (int i=0;i<B;++i)
for (int j=0;j<B;++j){
int t=(i^B-1)&(j^B-1);
for (int k=0;k<bit;++k)
if (t>>k&1)
same0[i][j]++;
// for (int k=0;k<bit;++k)
// if ((i>>k&1)==0 && (j>>k&1)==0)
// same0[i][j]++;
same0[i][j]=1<<same0[i][j];
same0_[i][j]=mo-same0[i][j];
// printf("(%d,%d) %d %d\n",i,j,(i^(B-1))&(j^(B-1)),same0[i][j]);
}
int _m=0;
for (int i=1;i<=m;++i){
int op=input(),x=input(),l=input(),r=input();
if (op==0){
int c=input();
c%=mo;
ans[i]=-1;
o[++_m]={0,x,l,c,i};
o[++_m]={0,x,r+1,mo-c,i};
}
else{
o[++_m]={1,x,l-1,mo-1,i};
o[++_m]={1,x,r,1,i};
}
}
cdq(1,_m);
// for (int i=1;i<=n;++i)
// if (o[i].op==0){
// int prei=o[i].x>>bit,suci=o[i].x&B-1;
// for (int j=i+1;j<=n;++j)
// if (o[j].op==1 && o[j].l>=o[i].l){
// int prej=o[j].x>>bit,sucj=o[j].x&B-1;
// int cnt=0,t=(o[i].x^n-1)&(o[j].x^n-1);
// for (int k=0;k<2*bit;++k)
// if (t>>k&1)
// cnt++;
// cnt=1<<cnt;
// ll tmp=/*(ll)same0[prei][prej]*same0[suci][sucj]*/cnt*((ll)o[i].c*o[j].c%mo)%mo;
// (ans[o[j].t]+=(ll)(o[j].l-o[i].l+1)*tmp)%=mo;
// }
// }
// int cnt=0;
for (int i=1;i<=m;++i)
if (ans[i]!=-1){
printf("%lld\n",ans[i]);
}
return 0;
}