6711. 【2020.06.09省選模擬】題2 and

題目


正解

首先考慮某個修改(設修改xx)對某次詢問(設修改yy)的影響。可以發現它的貢獻是區間交乘權值乘xxyy相同二進制位上的00的個數。
分塊是這種問題的常規套路。將數字分成28282^8*2^8的兩段。
先考慮單點修改的情況。
f(pre,suc)f(pre,suc)表示修改時前綴爲prepre,對詢問後綴爲sucsuc的影響。
修改的時候,找到對應的prepre,然後用282^8的時間處理它對每個後綴的影響。
詢問的時候,用282^8的時間枚舉prepre,然後找到對應的sucsuc,加起來。
這樣時間複雜度是O(nn)O(n\sqrt n)的。

在考慮對區間的貢獻。將左端點和右端點拆開,那麼就相當於將某個位置後面的數區間加,或者詢問前綴和。
於是cdqcdq分治,處理時間發生在前對時間發生後、且操作位置在前對操作位置在後的影響。
每個f(pre,suc)f(pre,suc)記一個一次函數就可以了。
於是時間複雜度O(nnlgn)O(n\sqrt n \lg n)


代碼

這題有點卡常數,所以當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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章