• 题解 Luogu P4891 序列


    题意

    给定两个长度为 \(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;
    }
    
    
  • 相关阅读:
    Docker(12)- docker run 命令详解
    adb 常用命令大全(7)- 其他实用功能
    adb 常用命令大全(6)- 模拟按键输入
    adb 常用命令大全(5)- 日志相关
    adb 常用命令大全(4)- 应用管理
    adb 常用命令大全(3)- 查看手机设备信息
    adb 常用命令大全(2)- 基础命令
    adb 常用命令大全(1)- 汇总
    Docker
    Docker(11)- docker ps 命令详解
  • 原文地址:https://www.cnblogs.com/liuzongxin/p/16479589.html
Copyright © 2020-2023  润新知