#线段树#洛谷 4428 [BJOI2018]二进制
题目
有一个长为 \(n\) 的二进制串,支持单个位置取反,对于这个二进制串的一个子区间,
求出其有多少位置不同的连续子串,满足在重新排列后(可包含前导0)是一个 3 的倍数。
分析
考虑对于单个位置\(2^i\bmod 3\)为\(1,2,1,2,\cdots\)
3的倍数有很多种情况,考虑补集转化,
设0的个数为\(c0\),1的个数为\(c1\),则不是3的倍数当且仅当
\]
由于支持单点修改,所以还需要一个线段树,
一个区间的答案等于左右区间的答案加上合并后多出的答案
一条一条考虑,上面这个只考虑\(c1=1\),再减掉\(c0\leq 1\)的情况
单考虑\(c1=1\),即需要维护前后缀0的最长长度\(l0,r0\),
为了少判断,还需要维护\(l1,r1\)表示只有1个1的前后缀个数
那合并后多出的答案就是\(lson.r1*rson.l0+lson.r0+rson.l1\)
然后对于\(c0=1\)的情况当且仅当一个0和一个1相邻,那么合并的时候直接判断即可
对于\(c0=0\)的情况由于下一种情况被放到上面处理所以没有重复
对于\(c1\bmod 2==1\&c0\leq 1\)的情况,
设\(f[0/1][0/1]\)表示前缀或后缀0的个数为0或1且1的个数为偶数或奇数,直接转移即可
代码
#include <cstdio>
#include <cctype>
#include <cstring>
#define rr register
using namespace std;
const int N=100011; typedef long long lll; int n,a[N];
struct rec{int lo,ro,co,cz,lz,rz,f[2][2],g[2][2]; lll w;}b[N<<2];
inline signed iut(){
rr int ans=0; rr char c=getchar();
while (!isdigit(c)) c=getchar();
while (isdigit(c)) ans=(ans<<3)+(ans<<1)+(c^48),c=getchar();
return ans;
}
inline void print(lll ans){
if (ans>9) print(ans/10);
putchar(ans%10+48);
}
inline rec pup(rec t0,rec t1){
rr rec t;
t.lz=t0.lz+(t0.co?0:t1.lz),t.rz=t1.rz+(t1.co?0:t0.rz);
t.co=t0.co+t1.co,t.cz=t0.cz+t1.cz;
t.lo=t0.lo+(t0.co?(t0.co==1?t1.lz:0):t1.lo);
t.ro=t1.ro+(t1.co?(t1.co==1?t0.rz:0):t0.ro);
for (rr int i=0;i<2;++i)
for (rr int j=0;j<2;++j){
t.f[i][j]=t0.f[i][j]+(i>=t0.cz?t1.f[i-t0.cz][(j^t0.co)&1]:0);
t.g[i][j]=t1.g[i][j]+(i>=t1.cz?t0.g[i-t1.cz][(j^t1.co)&1]:0);
}
t.w=t0.w+t1.w+1ll*t0.rz*t1.lo+1ll*t0.ro*t1.lz;
for (rr int i0=0;i0<2;++i0)
for (rr int i1=0;i1<2;++i1) if (i0+i1<2)
t.w+=1ll*t0.g[i0][0]*t1.f[i1][1]+1ll*t0.g[i0][1]*t1.f[i1][0];
if ((!t0.rz&&t1.lz)||(t0.rz&&!t1.lz)) --t.w;
return t;
}
inline void pdown(rec &t,int x){
memset(t.f,0,sizeof(t.f));
memset(t.g,0,sizeof(t.g));
if (x) t.lo=t.ro=t.co=t.w=1,t.cz=t.lz=t.rz=0,t.f[0][1]=t.g[0][1]=1;
else t.lo=t.ro=t.co=t.w=0,t.cz=t.lz=t.rz=1,t.f[1][0]=t.g[1][0]=1;
}
inline void build(int k,int l,int r){
if (l==r){pdown(b[k],a[l]); return;}
rr int mid=(l+r)>>1;
build(k<<1,l,mid);
build(k<<1|1,mid+1,r);
b[k]=pup(b[k<<1],b[k<<1|1]);
}
inline void update(int k,int l,int r,int x){
if (l==r){pdown(b[k],a[l]); return;}
rr int mid=(l+r)>>1;
if (x<=mid) update(k<<1,l,mid,x);
else update(k<<1|1,mid+1,r,x);
b[k]=pup(b[k<<1],b[k<<1|1]);
}
inline rec query(int k,int l,int r,int x,int y){
if (l==x&&r==y) return b[k];
rr int mid=(l+r)>>1;
if (y<=mid) return query(k<<1,l,mid,x,y);
else if (x>mid) return query(k<<1|1,mid+1,r,x,y);
else return pup(query(k<<1,l,mid,x,mid),query(k<<1|1,mid+1,r,mid+1,y));
}
signed main(){
n=iut();
for (rr int i=1;i<=n;++i) a[i]=iut();
build(1,1,n);
for (rr int T=iut();T;--T){
rr int opt=iut();
if (opt==1){
rr int x=iut();
a[x]^=1,update(1,1,n,x);
}else{
rr int l=iut(),r=iut();
rr rec t=query(1,1,n,l,r);
rr lll ans=1ll*(r-l+1)*(r-l+2)>>1;
print(ans-t.w),putchar(10);
}
}
return 0;
}
#线段树#洛谷 4428 [BJOI2018]二进制的更多相关文章
- Bzoj5294/洛谷P4428 [Bjoi2018]二进制(线段树)
题面 Bzoj 洛谷 题解 考虑一个什么样的区间满足重组之后可以变成\(3\)的倍数.不妨设\(tot\)为一个区间内\(1\)的个数.如果\(tot\)是个偶数,则这个区间一定是\(3\)的倍数,接 ...
- 线段树 洛谷P3932 浮游大陆的68号岛
P3932 浮游大陆的68号岛 题目描述 妖精仓库里生活着黄金妖精们,她们过着快乐,却随时准备着迎接死亡的生活. 换用更高尚的说法,是随时准备着为这个无药可救的世界献身. 然而孩子们的生活却总是无忧无 ...
- [线段树]洛谷P5278 算术天才⑨与等差数列
题目描述 算术天才⑨非常喜欢和等差数列玩耍. 有一天,他给了你一个长度为n的序列,其中第i个数为a[i]. 他想考考你,每次他会给出询问l,r,k,问区间[l,r]内的数从小到大排序后能否形成公差为k ...
- 区间连续长度的线段树——洛谷P2894 [USACO08FEB]酒店Hotel
https://www.luogu.org/problem/P2894 #include<cstdio> #include<iostream> using namespace ...
- AC日记——校门外的树 洛谷 P1047
题目描述 某校大门外长度为L的马路上有一排树,每两棵相邻的树之间的间隔都是1米.我们可以把马路看成一个数轴,马路的一端在数轴0的位置,另一端在L的位置:数轴上的每个整数点,即0,1,2,……,L,都种 ...
- 带修主席树 洛谷2617 支持单点更新以及区间kth大查询
题目链接:https://www.luogu.com.cn/problem/P2617 参考博客:https://blog.csdn.net/dreaming__ldx/article/details ...
- 洛谷P1582 倒水 二进制 lowbit __builtin_popcount
P1582 倒水:https://www.luogu.org/problemnew/show/P1582 题意: 给定n瓶装有1升的水瓶,每次可以把两瓶装水量相同的水和成一瓶,问最少还要增加几瓶装有1 ...
- 洛谷P1582 倒水 二进制的相关应用
https://www.luogu.org/problem/P1582 #include<bits/stdc++.h> using namespace std; long long N,K ...
- 洛谷P4427 [BJOI2018]求和
\(\Large\textbf{Description: } \large{一颗n个节点的树,m次询问,每次查询点i到点j的路径上所有节点点深度的k次方的和并对998244353取模(1\leq n, ...
- BZOJ5259/洛谷P4747: [Cerc2017]区间
BZOJ5259/洛谷P4747: [Cerc2017]区间 2019.8.5 [HZOI]NOIP模拟测试13 C.优美序列 思维好题,然而当成NOIP模拟题↑真的好吗... 洛谷和BZOJ都有,就 ...
随机推荐
- 将JavaBean对象转换为Map集合
使用jackson-databind可以将JavaBean对象属性转换为Map集合. 添加配置依赖: <dependency> <groupId>com.fasterxml.j ...
- Linux驱动开发笔记(三):基于ubuntu的helloworld驱动源码编写、makefile编写以及驱动编译加载流程测试
前言 前面学习了驱动的基础框架,上一篇编译了gcc7.3.0,那么为了方便很好的熟悉流程,本篇,将使用ubuntu18.04,直接编译ubuntu18.04的驱动,然后做好本篇文章的相关实战测试. ...
- 【Azure Developer】示例: 在中国区调用MSGraph SDK通过User principal name获取到User信息,如Object ID
问题描述 示例调用MSGraph SDK通过User principal name获取到User信息,如Object ID. 参考资料 选择 Microsoft Graph 身份验证提供程序 : ht ...
- 【Azure Developer】Springboot 集成 中国区的Key Vault 报错 AADSTS90002: Tenant 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx' not found
问题描述 Springboot 集成azure keyvault 报错,代码参考的官方文档:https://docs.microsoft.com/en-us/azure/developer/java/ ...
- 【Azure Developer】在使用中国区 Azure AD B2C时, AUTHORITY的值是什么呢?
问题描述 使用MSAL4J的SDK调用(源码地址:https://github.com/Azure-Samples/ms-identity-msal-java-samples/tree/main/3. ...
- OPPO 自研大规模知识图谱及其在数智工程中的应用
导读:OPPO 知识图谱是 OPPO 数智工程系统小布助手团队主导.多团队协作建设的自研大规模通用知识图谱,目前已达到数亿实体和数十亿三元组的规模,主要落地在小布助手知识问答.电商搜索等场景. 本文主 ...
- Java --- 多线程 创建线程的方式四: 使用线程池
1 package bytezero.thread2; 2 3 import java.security.Provider; 4 import java.util.concurrent.Executo ...
- 8、mysql的内存管理及优化
内存优化原则 1) 将尽量多的内存分配给MySQL做缓存,但要给操作系统和其他程序预留足够内存. 2) MyISAM 存储引擎的数据文件读取依赖于操作系统自身的IO缓存,因此,如果有MyISAM表,就 ...
- 实现一个 SEO 友好的响应式多语言官网 (Vite-SSG + Vuetify3) 我的踩坑之旅
在 2023 年的年底,我终于有时间下定决心把我的 UtilMeta 项目官网 进行翻新,主要的原因是之前的官网是用 Vue2 实现的一个 SPA 应用,对搜索引擎 SEO 很不友好,这对于介绍项目的 ...
- Zabbix“专家坐诊”第187期问答汇总
问题一 Q:zabbix server 5.0有办法不通过脚本监控SSL证书到期时间么? A:目前还是流行通过脚本方式去获取. Q:如果是通配符证书应该怎么监控? A:通过解析域名获取对应的过期时间的 ...