Codeforces 1340F - Nastya and CBS(分块+哈希)
首先看到这样的数据范围我们可以考虑分块,具体来说,对于每一块我们记录其中的括号是否能完全消掉,以及对其进行括号相消之后的括号序列(显然是一段右括号接上一段左括号)长什么样,那么对于一个块,我们显然可以在 \(\mathcal O(\sqrt{n})\) 的时间内对其求出其进行重构,因此每次修改完都重构一遍复杂度是不会出现问题的。
接下来考虑怎样查询一个区间是否是合法的括号序列,对于此题而言比较恶心的一点是,当我们合并两个块 \(x,y\) 时,要对两个块中间的部分进行括号相消时暴力跑复杂度是 \(\sqrt{n}\) 地,再加上总共查询可能会达到 \(\sqrt{n}\) 个块,单次查询的复杂度又退化到了 \(\mathcal O(n)\),稳稳地 T 掉。一种解决方法是指针,可作为一名从刚学 OI 开始就不喜欢指针的选手自然是不会选择这样的写法的,因此这里介绍一种不用指针的写法。考虑我们暴力合并的过程,对于一个块而言我们肯定是先用这一块的一段右括号去消前面的一段左括号,再加入一段右括号,而如果我们把每次加入的一段右括号视为一个连续段的话,那么每次消除左括号时最多将一个左括号的连续段劈成两段。这样思路不就出来了吗,我们考虑对于每一块,将这一块消除后剩余的左括号压入一个 vector,并用一个三元组 \((x,l,r)\) 描述一个连续段,表示这个连续段是第 \(x\) 块消除后剩余的左括号序列的第 \(l\) 至第 \(r\) 个元素,然后我们维护一个栈存储这些三元组存储这些未消完的括号组成的连续段,这样每次与一段长度为 \(L\) 的右括号序列进行消除时只需取出栈顶的 \(L\) 个元素,哈希判断括号序列是否相等即可,如果最后一段消完后还有剩余就将剩余部分压入栈中。根据之前的推论,每个三元组恰好进出栈各一次,而每次消除最多增加一个三元组,因此总复杂度是严格 \(\mathcal O(m\sqrt{n})\) 的。
细节有一点点多,不过相信聪明的读者们定能够将每种情况都分析清楚(
const int MAXN=1e5;
const int BLK=316;
const u64 B=191;
u64 pw[MAXN+5];
int n,k,qu,a[MAXN+5],blk_cnt,blk_sz;
int bel[MAXN+5],L[BLK+5],R[BLK+5];
bool ok[BLK+5];
vector<int> lft[BLK+5],rit[BLK+5];
vector<u64> lft_hs[BLK+5];u64 rit_hs[BLK+5];
struct node{int x,l,r;u64 hs;};
u64 gethash(int x,int l,int r){
	return (lft_hs[x][l]-((r+1==lft[x].size())?0:lft_hs[x][r+1]*pw[r-l+1]));
}
void redone(int x){
	stack<int> stk;ok[x]=1;lft[x].clear();rit[x].clear();
	for(int i=L[x];i<=R[x];i++){
		if(a[i]<0){
			if(!stk.empty()&&stk.top()^(-a[i])) return ok[x]=0,void();
			else if(stk.empty()) rit[x].pb(-a[i]);else stk.pop();
		} else stk.push(a[i]);
	} while(!stk.empty()) lft[x].pb(stk.top()),stk.pop();
	lft_hs[x].resize(lft[x].size(),0);rit_hs[x]=0;
	for(int i=(int)(lft[x].size())-1;~i;i--) lft_hs[x][i]=((i+1==lft[x].size())?0:lft_hs[x][i+1])*B+lft[x][i];
	for(int i=0;i<rit[x].size();i++) rit_hs[x]+=rit[x][i]*pw[i];
//	printf("Block %d:\n",x);
//	for(int i=0;i<lft[x].size();i++) printf("%d ",lft[x][i]);printf("\n");
//	for(int i=0;i<rit[x].size();i++) printf("%d ",rit[x][i]);printf("\n");
}
bool query(int l,int r){
	if(bel[l]==bel[r]){
		stack<int> stk;
		for(int i=l;i<=r;i++){
			if(a[i]<0){
				if(stk.empty()||stk.top()^(-a[i])) return 0;
				stk.pop();
			} else stk.push(a[i]);
		} return stk.empty();
	} for(int i=bel[l]+1;i<bel[r];i++) if(!ok[i]) return 0;
	stack<node> stk;
	for(int i=l;i<=R[bel[l]];i++){
		if(a[i]<0){
			if(stk.empty()) return 0;node t=stk.top();stk.pop();
			u64 hs=(!~t.l)?t.hs:gethash(t.x,t.l,t.l);if(hs+a[i]) return 0;
			if(t.l^t.r) stk.push({t.x,t.l+1,t.r,gethash(t.x,t.l+1,t.r)});
		} else stk.push({bel[l],-1,-1,a[i]});
	}
	for(int i=bel[l]+1;i<bel[r];i++){
		int need=rit[i].size(),clen=0;u64 cur_hs=0;
		while(!stk.empty()&&need){
			node t=stk.top();stk.pop();int len=t.r-t.l+1;
			if(need<=len){
				if(!~t.l) cur_hs+=t.hs*pw[clen];
				else cur_hs+=gethash(t.x,t.l,t.l+need-1)*pw[clen];
				if(need^len) stk.push({t.x,t.l+need,t.r,gethash(t.x,t.l+need,t.r)});
				need=0;break;
			} else {
				cur_hs+=t.hs*pw[clen];
				need-=len;clen+=len;
			}
		} if(need) return 0;if(cur_hs^rit_hs[i]) return 0;
		if(!lft[i].empty()) stk.push({i,0,lft[i].size()-1,lft_hs[i][0]});
	}
	for(int i=L[bel[r]];i<=r;i++){
		if(a[i]<0){
			if(stk.empty()) return 0;node t=stk.top();stk.pop();
			u64 hs=(!~t.l)?t.hs:gethash(t.x,t.l,t.l);if(hs+a[i]) return 0;
			if(t.l^t.r) stk.push({t.x,t.l+1,t.r,gethash(t.x,t.l+1,t.r)});
		} else stk.push({bel[l],-1,-1,a[i]});
	} return stk.empty();
}
int main(){
	scanf("%d%d",&n,&k);
	for(int i=(pw[0]=1);i<=n;i++) pw[i]=pw[i-1]*B;
	blk_cnt=(int)pow(n,0.5);blk_sz=(n-1)/blk_cnt+1;
	for(int i=1;i<=n;i++) scanf("%d",&a[i]);
	for(int i=1;i<=blk_cnt;i++){
		L[i]=(i-1)*blk_sz+1;R[i]=min(i*blk_sz,n);
//		printf("%d %d\n",L[i],R[i]);
		for(int j=L[i];j<=R[i];j++) bel[j]=i;
	}
	for(int i=1;i<=blk_cnt;i++) redone(i);
	scanf("%d",&qu);
	while(qu--){
		int opt;scanf("%d",&opt);
		if(opt==1){
			int p,x;scanf("%d%d",&p,&x);a[p]=x;
			redone(bel[p]);
		} else {
			int l,r;scanf("%d%d",&l,&r);
			printf("%s\n",query(l,r)?"Yes":"No");
		}
	}
	return 0;
}
/*
10 10
4 4 4 -4 1 -1 -4 8 -8 -4
1
2 2 9
10 1
9 3 7 -7 4 -4 -3 1 -1 -9
1
2 1 10
*/
												
											Codeforces 1340F - Nastya and CBS(分块+哈希)的更多相关文章
- HDU 4391 - Paint The Wall - 分块哈希入门
		
题目链接 : http://acm.hdu.edu.cn/showproblem.php?pid=4391 题意 : 给一段区间, 有两种操作 1 : 给 x 到 y 的区间染色为 z 2 : 查询 ...
 - Codeforces Gym 100338B Spam Filter 字符串哈希+贝叶斯公式
		
原题链接:http://codeforces.com/gym/100338/attachments/download/2136/20062007-winter-petrozavodsk-camp-an ...
 - CodeForces 1202F(数论,整除分块)
		
题目 CodeForces 1213G 做法 假设有\(P\)个完整的循环块,假设此时答案为\(K\)(实际答案可能有多种),即每块完整块长度为\(K\),则\(P=\left \lfloor \fr ...
 - Codeforces 1290D - Coffee Varieties(分块暴力+完全图的链覆盖)
		
Easy version:Codeforces 题面传送门 & 洛谷题面传送门 Hard version:Codeforces 题面传送门 & 洛谷题面传送门 发现自己交互题烂得跟 s ...
 - codeforces#1136E. Nastya Hasn't Written a Legend(二分+线段树)
		
题目链接: http://codeforces.com/contest/1136/problem/E 题意: 初始有a数组和k数组 有两种操作,一,求l到r的区间和,二,$a_i\pm x$ 并且会有 ...
 - Codeforces 1136E - Nastya Hasn't Written a Legend - [线段树+二分]
		
题目链接:https://codeforces.com/problemset/problem/1136/E 题意: 给出一个 $a[1 \sim n]$,以及一个 $k[1 \sim (n-1)]$, ...
 - Codeforces 1136D - Nastya Is Buying Lunch - [贪心+链表+map]
		
题目链接:https://codeforces.com/problemset/problem/1136/D 题意: 给出 $1 \sim n$ 的某个排列 $p$,再给出若干 $(x,y)$ 表示当序 ...
 - Codeforces 1136C - Nastya Is Transposing Matrices
		
题目链接:https://codeforces.com/problemset/problem/1136/C 题意: 给出 $n \times m$ 的矩阵 $A,B$,你可以对其中任意某个 $k \t ...
 - codeforces E - Anya and Cubes 分块处理 暴力搜索
		
说的是给了n个立方体,立方体从1标号到n,每个立方体上有一个数字, 你有 k 个机会 使得其中 k个数位他们自己的阶乘,(自然使用可以少于k次机会,每个立方体最多被使用1次) ,那么求出你从这n个立方 ...
 
随机推荐
- Vulnhub实战-grotesque3靶机👻
			
Vulnhub实战-grotesque3靶机 靶机地址:http://www.vulnhub.com/entry/grotesque-301,723/ 1.靶机描述 2.主机探测,端口扫描 我们在vm ...
 - [对对子队]Beta设计和计划
			
需求再分析 Alpha阶段用户反馈的问题主要有三个 新手引导部分没有明确指出合成按钮可以使用下拉框切换目标,因此不少玩家卡在第三关 觉得合成动画太长,希望可以快进或者跳过 对游戏目标很迷惑,不知道为什 ...
 - 乘风破浪,遇见上一代操作系统Windows 10 - 抢鲜尝试安装新微软商店(Microsoft Store)
			
背景 在微软官方文章的<十一项关于微软商店新知>中提到: 新的微软商店现在可在Windows 11上找到,我们很高兴地分享,它将在未来几个月内提供给Windows 10客户!我们将很快分享 ...
 - 示波器分析I2C时序波形图
			
对于嵌入式开发的朋友来说,I2C协议实在是再熟悉不过了,有太多的器件,采用的都是通过I2C来进行相应的设置.今天,我们就随便聊聊这个I2C协议. I2C协议中最重要的一点是I2C地址.这个地址有7位和 ...
 - https的加密解密过程
			
前置知识 SSL是90年代Netscape弄出来的一套东西,为的是解决HTTP协议明文传输数据的问题.后来SSL慢慢成了事实上的标准,于是IETF就把SSL标准化了,名字叫做TLS,TLS 1.0其实 ...
 - cf 12B Correct Solution?(贪心)
			
题意: 一个数a,一个数b. 现在要将a的每一位上的数字重新整理,生成一个新的不含前导0的数a'. 问a'是否等于b. 思路: a上每一位的数字从小到大排序,找到最小的非零数和第一位交换. 代码: c ...
 - 百亿级小文件存储,JuiceFS 在自动驾驶行业的最佳实践
			
自动驾驶是最近几年的热门领域,专注于自动驾驶技术的创业公司.新造车企业.传统车厂都在这个领域投入了大量的资源,推动着 L4.L5 级别自动驾驶体验能尽早进入我们的日常生活. 自动驾驶技术实现的核心环节 ...
 - js this指向汇总
			
this指向 普通函数 window 定时器函数 window 事件函数 事件源 箭头函数 父function中的this,没有就是window 对象函数 对象本身 构造函数 实例化 ...
 - python环境搭建、pycharm安装
			
一. 实验目标 (1) Python环境搭建 (2) 会pycharm安装和使用 (3) 了解python程序设计流程 二. 实验内容 1.勾选Add Python 3.7 ...
 - Python小练习之验证“哥德巴赫猜想”
			
设计内容:任何一个大于2的偶数都可以分解为两个素数之和,这就是著名的哥达巴赫猜想. 设计要求:要求输入一个大于2的偶数,程序运行后,输出两个素数,其和正好等于该偶数. 1. 实验代码(知道是你们 ...