ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

题解 Luogu P4891 序列

2022-07-14 22:31:23  阅读:120  来源: 互联网

标签:cur int 题解 void leq tag Luogu P4891 operatorname


题意

给定两个长度为 \(n\) 的非负整数序列 \(A,B\),并定义数列 \(C\),\(C_i = \max\limits_{j=1}^{i}{A_i}\)。

有 \(q\) 次操作,每次对 \(A\) 和 \(B\) 的某个位置进行修改,然后询问 \(\prod \limits_{i=1}^{n} \min\{B_i,C_i\} \bmod 10^9+7\)。保证修改之后不小于原数。

\(1 \leq n ,q \leq 10^5\),任意时刻 \(0 \leq A_i,B_i \leq 10^9\)

题解

考虑一个修改的影响。\(B\) 的影响是单点的,但修改 \(A_i\) 的影响是一段以 \(i\) 开始的区间。

注意到这个区间修改比较阴间,因为维护的信息非常怪,不太能我不会线段树维护。考虑分块,维护块内的答案。对于修改 \(B_i\) 直接暴力重构块就行了。接下来重点讨论怎么维护修改了 \(A_i\) 之后的 \(C\)。

我们发现 \(A_i\) 被修改了之后会产生一个 \([i,n]\) 的 \(C\) 序列区间取 \(\max\) 操作。套路,散块暴力重构,整块直接打标记。考虑 \(\operatorname{tag}=k\) 的时候的答案。

分类讨论。

  • \(B_j \leq C_j\)

    此时 \(j\) 的贡献一定是 \(B_i\)。

  • \(C_j \leq \operatorname{tag} \leq B_j\)

    此时贡献是 \(\operatorname{tag}\)。

  • \(C_j \leq B_j \leq \operatorname{tag}\)

    此时贡献是 \(B_j\)。

  • \(\operatorname{tag} \leq C_j \leq \operatorname{B_j}\)

    贡献是 \(C_j\)。

考虑把贡献不为 \(\operatorname{tag}\) 的部分记下来,记作 \(mul\)。贡献为 \(\operatorname{tag}\) 的部分直接记录指数 \(c\)。显然第一种情况的 \(B_j\) 要乘到 \(mul\) 里面。然后维护后面三种情况。注意到 \(\operatorname{tag}\) 单调不减,于是一个 \(j\) 的贡献一定是先在第四种情况,然后第二种,最后第三种。

把所有 \(B_j \geq C_j\) 的 \(C_j\) 和 \(B_j\) 放一起排序,\(\operatorname{tag}\) 从前往后扫所有比它小的数,扫到一个 \(C_j\) 就说明是第二种情况,\(mul\) 除掉 \(C_j\),然后贡献多了一个 \(\operatorname{tag}\)。扫到一个 \(B_j\) 说明是第三种情况了,贡献少一个 \(\operatorname{tag}\),\(mul\) 乘上 \(B_j\)。

块内答案就是 \(mul \times \operatorname{tag}^{c}\),于是查询是根号的。

复杂度还有个快速幂的 \(\log\) 和排序的 \(\operatorname{log}\),于是是 \(O(n \sqrt n \log \max W)\),其中 \(W\) 是值域,默认 \(n,q\) 同阶。

另外可能会乘 \(0\) 和除 \(0\),需要精细实现一下。具体见代码。

# include <bits/stdc++.h>
const int N=100010,INF=0x3f3f3f3f,BLEN=410,MOD=1e9+7;
typedef long long ll;
int bsiz,blo[N];
int n,m;
int tc[N],tb[N],ta[N];
inline int qpow(ll d,ll p){ 
	ll ans=1;
	while(p){
		if(p&1) ans=ans*d%MOD;
		p>>=1,d=d*d%MOD;
	}
	return ans;
}
struct Prod{ // 支持乘 0 和除 0
	int z,cur; // z 是现在乘了的 0 的个数, cur 是除了 0 以外部分的乘积
	inline void setv(int x){ 
		z=0,cur=x;
		return;
	}
	inline void mul(int x){
		x?(cur=1ll*cur*x%MOD):(++cur);
		return;
	}
	inline void div(int x){
		x?(cur=1ll*cur*qpow(x,MOD-2)%MOD):(--cur);
		return;
	}
	inline int getv(void){
		return (!z)*cur; 
	}
};
struct Block{
	int len,c[BLEN],b[BLEN],tag,pos,lbc,L,R;
	Prod ans;
	std::vector <std::pair <int,int> > S;
	inline void init(int cl,int cr){ // 初始化
		len=cr-cl+1,L=cl,R=cr;
		for(int i=0;i<len;++i) c[i+1]=tc[cl+i],b[i+1]=tb[cl+i];
		return;
	}
	inline void remake(void){ // 暴力重构
		for(int i=1;i<=len;++i) c[i]=std::max(c[i],tag); // 下放标记
		ans.setv(1);
		for(int i=1;i<=len;++i) ans.mul(std::min(c[i],b[i]));
		S.clear();
		for(int i=1;i<=len;++i) if(b[i]>c[i]) S.push_back(std::make_pair(b[i],1)),S.push_back(std::make_pair(c[i],0));
		std::sort(S.begin(),S.end()),pos=lbc=0; // 归零 c 和 pos, 重新排序
	}
	inline void modifytag(int x){
		if(x<=tag) return;
		tag=x;
		while(pos<(int)S.size()&&S[pos].first<=tag){
			if(S[pos].second) --lbc,ans.mul(S[pos].first);
			else ++lbc,ans.div(S[pos].first);
			++pos;
		}
		return;
	}
	inline int query(void){
		return 1ll*ans.getv()*qpow(tag,lbc)%MOD;
	}
}B[BLEN];

inline int read(void){
	int res,f=1;
	char c;
	while((c=getchar())<'0'||c>'9')
		if(c=='-')f=-1;
	res=c-48;
	while((c=getchar())>='0'&&c<='9')
		res=res*10+c-48;
	return res*f;
}
void print(int x){
	if(x>9) print(x/10);
	putchar(x%10+'0');
	return; 
}
signed main(void){
	n=read(),m=read(),bsiz=floor(sqrt(n)+0.5);
	for(int i=1;i<=n;++i) ta[i]=read(),blo[i]=(i-1)/bsiz+1;
	for(int i=1;i<=n;++i) tb[i]=read(),tc[i]=std::max(tc[i-1],ta[i]);
	for(int i=1;i<=blo[n];++i){
		B[i].init((i-1)*bsiz+1,std::min(i*bsiz,n)),B[i].remake();
	}
	while(m--){
		int opt=read(),pos=read(),v=read();
		if(opt){
			int idx=blo[pos];
			B[idx].b[pos-B[idx].L+1]=v;
			B[idx].remake(); // 重构块
		}else{
			int idx=blo[pos];
			for(int i=pos;i<=B[idx].R;++i) B[idx].c[i-B[idx].L+1]=std::max(B[idx].c[i-B[idx].L+1],v); // 散块暴力修改
			B[idx].remake(); // 重构
			for(int i=idx+1;i<=blo[n];++i) B[i].modifytag(v);
		}
		int ans=1;
		for(int i=1;i<=blo[n];++i) ans=1ll*ans*B[i].query()%MOD;
		print(ans),puts("");
	}
	
	return 0;
}

标签:cur,int,题解,void,leq,tag,Luogu,P4891,operatorname
来源: https://www.cnblogs.com/liuzongxin/p/16479589.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有