#线段树#洛谷 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都有,就 ...
随机推荐
- Miniconda安装和使用
Miniconda概述 Miniconda是什么? 要解释Miniconda是什么,先要弄清楚什么是Anaconda,它们之间的关系是什么? 而要知道Anaconda是什么,最先要明白的是搞清楚什么是 ...
- Vulnhub内网渗透DC-6靶场通关
个人博客 xzajyjs.cn IP DC-6: 192.168.168.4 Kali: 192.168.168.5 信息搜集 arp-scan -l # nmap -sn 192.168.168.0 ...
- CentOS6.8下yum安装Nginx
在/etc/yum.repos.d/目录下创建一个源配置文件nginx.repo: cd /etc/yum.repos.d/ vim nginx.repo 填写如下内容: [nginx] name=n ...
- 【Azure Key Vault】使用Azure CLI获取Key Vault 机密遇见问题后使用curl命令来获取机密内容
问题描述 在使用Azure Key Vault的过程中,遇见无法获取机密信息,在不方便直接写代码的情况下,快速使用Azure CLI指令来验证当前使用的认证是否可以获取到正确的机密值. 使用CLI的指 ...
- 【Azure Redis 缓存】Lettuce 连接到Azure Redis服务,出现15分钟Timeout问题
问题描述 在Java应用中,使用 Lettuce 作为客户端SDK与Azure Redis 服务连接,当遇见连接断开后,长达15分钟才会重连.导致应用在长达15分的时间,持续报错Timeout 问题解 ...
- 【Azure 应用服务】App Service for Linux环境中,如何解决字体文件缺失的情况
问题描述 部署在App Service for Linux环境中的Web App.出现了字体文件缺失的问题,页面显示本来时中文的地方,区别变为方框占位. 问题分析 在应用中,通常涉及到显示问题的有两个 ...
- Nebula Graph|如何打造多版本文档中心
本文首发于 Nebula Graph Community 公众号 世界上没有完美的产品,每个不完美的产品都需要一份文档. 为什么需要文档 打造出一款产品后,我们需要一份文档来回答以下问题: 设计这款产 ...
- Codeforces Round 734 (Div. 3)B2. Wonderful Coloring - 2(贪心构造实现)
思路: 分类讨论: 当一个数字出现的次数大于等于k,那么最多有k个能被染色, 当一个数字出现的次数小于k,南那么这些数字都可能被染色 还有一个条件就是需要满足每个颜色的数字个数一样多,这里记出现次数小 ...
- Docker下搭建MySql主从复制
在Docker环境下搭建MySql主从复制,阅读此文章默认读者具备基础的Docker命令操作. 一.环境 1.Docker版本:Docker version 24.0.5, build ced0996 ...
- 真实开发中-redis在项目中的应用场景
一.需求描述 从自己当前负责参与开发的一个项目中来看,redis主要的应用场景有如下几个,第一个是保存用户信息,这个需要频繁的获取.比如 在打开某一个页面进行查询时,就先需要获取用户信息,看用户是否具 ...