! BJOI2018二进制

时间:2020-03-26
本文章向大家介绍! BJOI2018二进制,主要包括! BJOI2018二进制使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。


\(n,m,1e5\)

二进制没有位除3的余数是以12121212……循环的

我们用总数减去不合法情况:

  1. 只有1个1,0的个数>=2(保证不重复)
  2. 奇数个1,0的个数<2

考虑用线段树解决

每一点存

\(dl[0/1][0/1]\),左端点起,0的个数,1的个数的偶奇的方案数,\(dr\)同理

\(fl[0/1/2]\),左端点起,一个1,0/1/>=2个0的方案数,\(fr\)同理

在记录0/1的个数,左起/右起0的个数,答案

讨论更新即可

时间复杂度\(O(nlog_n)\)

#include<bits/stdc++.h>
using namespace std;
#define int long long
inline int read(){
	int x=0,f=1;char c=getchar();
	while(!isdigit(c)){if(c=='-')f=-1;c=getchar();}
	while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=getchar();}
	return f==1?x:-x;
}
const int N=1e5+4;
struct node{
	int dl[2][2],dr[2][2],fl[3],fr[3],s0,s1,l0,r0,s;
	//左端点起 0出现次数0/1 1的奇偶1/0  左端点起1的个数1个0的个数0/1/>=2
	inline void init(){
		memset(dl,0,sizeof(dl));
		memset(dr,0,sizeof(dr));
		memset(fl,0,sizeof(fl));
		memset(fr,0,sizeof(fr));
		s0=s1=l0=r0=s=0;
	} 
	node(){init();}
	inline void pre(int x){
		init();
		if(x)dl[0][1]=dr[0][1]=fl[0]=fr[0]=s1=s=1;
		else dl[1][0]=dr[1][0]=s0=l0=r0=1;
	}
	inline node operator +(const node &a)const{
		static node ret;
		memcpy(ret.dl,dl,sizeof(dl));
		memcpy(ret.fl,fl,sizeof(fl));
		memcpy(ret.dr,a.dr,sizeof(a.dr));
		memcpy(ret.fr,a.fr,sizeof(a.fr));
		for(int i=0;i+s0<2;i++)
			for(int v=0;v^2;v++)
				ret.dl[s0+i][v^(s1&1)]+=a.dl[i][v];
		for(int i=0;i+a.s0<2;i++)
			for(int v=0;v^2;v++)
				ret.dr[a.s0+i][v^(a.s1&1)]+=dr[i][v];
		for(int i=0;i<3;i++){
			if(!s1)ret.fl[min(2ll,i+s0)]+=a.fl[i];
			if(!a.s1)ret.fr[min(2ll,i+a.s0)]+=fr[i];
		}
		if(s1==1&&a.l0){
			ret.fl[min(2ll,s0+a.l0)]+=1;
			ret.fl[2]+=a.l0-1;
		}
		if(a.s1==1&&r0){
			ret.fr[min(2ll,a.s0+r0)]+=1;
			ret.fr[2]+=r0-1;
		}
		ret.l0=l0+(!s1?a.l0:0);//括号括起来 
		ret.r0=a.r0+(!a.s1?r0:0);
		ret.s0=s0+a.s0;
		ret.s1=s1+a.s1;
		ret.s=s+a.s;
		ret.s+=dr[0][0]*(a.dl[0][1]+a.dl[1][1])+dr[0][1]*(a.dl[0][0]+a.dl[1][0])+dr[1][0]*a.dl[0][1]+dr[1][1]*a.dl[0][0];
		if(r0)ret.s+=r0*(a.fl[0]+a.fl[1]+a.fl[2])-a.fl[0];
		if(a.l0)ret.s+=a.l0*(fr[0]+fr[1]+fr[2])-fr[0];
		return ret;
	}
}t[N<<2];
#define lc (p<<1)
#define rc (p<<1|1)
int n,m,a[N<<2];
void build(int p,int l,int r){
	if(l==r){
		t[p].pre(a[l]);
		return;
	}
	int mid=l+r>>1;
	build(lc,l,mid);
	build(rc,mid+1,r);
	t[p]=t[lc]+t[rc];
} 
void modify(int p,int l,int r,int x){
	if(l==r){
		t[p].pre(a[l]);
		return;
	}
	int mid=l+r>>1;
	if(x<=mid)modify(lc,l,mid,x);
	else modify(rc,mid+1,r,x);
	t[p]=t[lc]+t[rc];
}
node query(int p,int l,int r,int ql,int qr){
	if(ql<=l&&r<=qr)return t[p];
	int mid=l+r>>1;
	if(qr<=mid)return query(lc,l,mid,ql,qr);
	if(mid<ql)return query(rc,mid+1,r,ql,qr);
	return query(lc,l,mid,ql,qr)+query(rc,mid+1,r,ql,qr);
}
signed main(){
	n=read();
	for(int i=1;i<=n;i++)a[i]=read();
	build(1,1,n);
	m=read();
	while(m--){
		static int op,x,y;
		op=read();x=read();
		if(op==1){
			a[x]^=1;
			modify(1,1,n,x);
		}
		else{
			y=read();
			cout<<(y-x+1)*(y-x+2)/2-query(1,1,n,x,y).s<<"\n";
		}
	}
	return (0-0);
}

原文地址:https://www.cnblogs.com/aurora2004/p/12575317.html