wannafly25 E 01串

链接 wannafly25 E 01串

  • 给出一个(01)串,有两种操作,操作一是将某一个位置的数字修改,操作二是询问某一个区间,将这个区间看做(1)个二进制数,可以随意加减(2)的幂次,问将这个数变为(0)的最小操作步数,(n,qleq 3*10^5)
  • 动态dp,线段树优化(dp)
  • (f_{i,01})表示当前在(i)号点,是否有进位的最小步骤,转移大力讨论。
  • 把每个转移看作一个(2*2)的矩阵,实际上一个(Dp)就是一堆矩阵的和,线段树维护矩阵和和单点修改即可。
  • 转移$$f_{i,j}=min(f_{i,0}+f_{0,j},f_{i,1}+f_{1,j})$$
  • 初始条件$$f_{0,0}=x,f_{1,1}=!x,f_{1,0}=f_{0,1}=1$$
  • 复杂度(O(nlogn))
#include<bits/stdc++.h>
#define R register int
using namespace std;
const int N=300001;
int n,q,w[N],Le[N*4],Ri[N*4];char S[N];
int gi(){
    R x=0,k=1;char c=getchar();
    while(c!='-'&&(c<'0'||c>'9'))c=getchar();
    if(c=='-')k=-1,c=getchar();
    while(c>='0'&&c<='9')x=(x<<3)+(x<<1)+c-'0',c=getchar();	
    return x*k;
}
struct Mar{
	int s[2][2];
	void init(R x){
		s[0][0]=x,s[1][1]=(!x);
		s[1][0]=s[0][1]=1;
	}
}z,te[N*4];
Mar operator + (Mar x,Mar y){
	for(R i=0;i<=1;++i)
		for(R j=0;j<=1;++j)
			z.s[i][j]=min(x.s[i][0]+y.s[0][j],x.s[i][1]+y.s[1][j]);
	return z;
}
void build(R le,R ri,R i){
	Le[i]=le,Ri[i]=ri;
	if(le==ri){te[i].init(w[le]);return ;}
	R mid=(Le[i]+Ri[i])>>1,ls=(i<<1),rs=(ls|1);
	build(le,mid,ls),build(mid+1,ri,rs);
	te[i]=te[ls]+te[rs];
}
Mar quy(R le,R ri,R i){
	if(Le[i]==le&&Ri[i]==ri)return te[i];
	R mid=(Le[i]+Ri[i])>>1,ls=(i<<1),rs=(ls|1);
	if(ri<=mid)return quy(le,ri,ls);
	else if(le>mid)return quy(le,ri,rs);
	else return quy(le,mid,ls)+quy(mid+1,ri,rs);
}
void mdf(R pos,R v,R i){
	if(Le[i]==Ri[i]){w[pos]=v,te[i].init(v);return ;}
	R mid=(Le[i]+Ri[i])>>1,ls=(i<<1),rs=(ls|1);
	if(pos<=mid)mdf(pos,v,ls);else mdf(pos,v,rs);
	te[i]=te[ls]+te[rs];
}
int main(){
	n=gi(),scanf("%s",S+1);
	for(R i=1;i<=n;++i)w[i]=S[i]-'0';
	build(1,n,1),q=gi();
	while(q--){
		R op=gi(),u=gi(),v=gi();
		if(op==1)printf("%d
",quy(u,v,1).s[0][0]);
		else mdf(u,v,1);
	}
	return 0;
}

原文地址:https://www.cnblogs.com/Tyher/p/9871238.html