【题解】Loj #6029. 「雅礼集训 2017 Day1」市场

#6029. 「雅礼集训 2017 Day1」市场

题目描述

image
数据范围1e5

题解

对于这种数据貌似可以快速缩小的题目,我们可以用势能分析来证明其某暴力或者什么做法的复杂度。
设某节点的势能函数是点内数的极差,每次除一个数极差一定会减半,总共会被除 log 次。
然而有特殊情况,如果考虑下取整产生的误差,可能有除法之后极差不变的情况。
如 5,6,5,6 ,在除以 3 之后变为 2,3,2,3 加上 3 之后又变回 5,6,5,6。
这样,每次除法操作都需要暴力,复杂度退化。
我们发现,下取整最多带来 1 的偏差,所以极差为 1 时才有可能除完极差不变。
于是我们可以维护最值,当最大值和最小值除d与原来数的差不变时,可以直接替换为加法操作。

 
有一道差不多的题,是把除法操作替换成根号。
类似的还有取min,max的,都可以用势能分析。

#include<bits/stdc++.h>
using namespace std;
#define int long long
#define ls (u*2)
#define rs (u*2+1)
inline int rd(){
	int f=1,j=0;
	char w=getchar();
	while(!isdigit(w)){
		if(w=='-')f=-1;
		w=getchar();
	}
	while(isdigit(w)){
		j=j*10+w-'0';
		w=getchar();
	}
	return f*j;
}
const int N=100010;
int n,m,sum[N];
int len[N*4],ma[N*4],mi[N*4],tag[N*4],tr[N*4];
inline void update(int u){
	ma[u]=max(ma[ls],ma[rs]),mi[u]=min(mi[ls],mi[rs]);
	tr[u]=tr[ls]+tr[rs];
	return ;
}
inline void pushdown(int u){
	if(!tag[u])return ;
	tag[ls]+=tag[u],tag[rs]+=tag[u];
	ma[ls]+=tag[u],ma[rs]+=tag[u],mi[ls]+=tag[u],mi[rs]+=tag[u];
	tr[ls]+=tag[u]*len[ls],tr[rs]+=tag[u]*len[rs];
	tag[u]=0;
	return ;
}
void built(int u,int l,int r){
	len[u]=r-l+1;
	if(l==r)return tr[u]=ma[u]=mi[u]=sum[l],void(0);
	int mid=(l+r)/2;
	built(ls,l,mid),built(rs,mid+1,r);
	update(u);
	return ;
}
void modify1(int u,int l,int r,int L,int R,int sumn){
	if(L<=l&&r<=R)return ma[u]+=sumn,mi[u]+=sumn,tag[u]+=sumn,tr[u]+=sumn*len[u],void(0);
	int mid=(l+r)/2;
	pushdown(u);
	if(L<=mid)modify1(ls,l,mid,L,R,sumn);
	if(R>mid)modify1(rs,mid+1,r,L,R,sumn);
	update(u);
	return ;
}
void modify2(int u,int l,int r,int L,int R,int d){
//	cout<<u<<":"<<l<<" "<<r<<"-"<<L<<" "<<R<<"-"<<d<<":"<<ma[u]<<" "<<mi[u]<<"\n"; 
	int mid=(l+r)/2;
	if(l<r)pushdown(u);
	if(L<=l&&r<=R){
		int x=ma[u]-ma[u]/d+(ma[u]<0&&ma[u]%d!=0),y=mi[u]-mi[u]/d+(mi[u]<0&&mi[u]%d!=0);
//		cout<<u<<":"<<l<<" "<<r<<"-"<<L<<" "<<R<<"-"<<d<<":"<<ma[u]<<" "<<mi[u]<<"|||"<<x<<" "<<y<<"\n"; 
		if(x==y)return ma[u]-=x,mi[u]-=x,tag[u]-=x,tr[u]-=x*len[u],void(0);
		modify2(ls,l,mid,L,R,d),modify2(rs,mid+1,r,L,R,d);
		update(u);
		return ;
	}
	if(L<=mid)modify2(ls,l,mid,L,R,d);
	if(R>mid)modify2(rs,mid+1,r,L,R,d);
	update(u);
	return ;
}
int query3(int u,int l,int r,int L,int R){
	if(L<=l&&r<=R)return mi[u];
	pushdown(u);
	int mid=(l+r)/2,ansn=1e18;
	if(L<=mid)ansn=min(query3(ls,l,mid,L,R),ansn);
	if(R>mid)ansn=min(query3(rs,mid+1,r,L,R),ansn);
	return ansn;
}
int query4(int u,int l,int r,int L,int R){
	if(L<=l&&r<=R)return tr[u];
	pushdown(u);
	int mid=(l+r)/2,ansn=0;
	if(L<=mid)ansn+=query4(ls,l,mid,L,R);
	if(R>mid)ansn+=query4(rs,mid+1,r,L,R);
	return ansn;
}
signed main(){
//	freopen("market0.in","r",stdin);
	n=rd(),m=rd();
	for(int i=1;i<=n;i++)sum[i]=rd();
	built(1,1,n);
	for(int i=1;i<=m;i++){
		int k=rd();
		if(k==1){
			int l=rd()+1,r=rd()+1,c=rd();
			modify1(1,1,n,l,r,c);
		}
		else if(k==2){
			int l=rd()+1,r=rd()+1,d=rd();
			modify2(1,1,n,l,r,d);
		}
		else if(k==3){
			int l=rd()+1,r=rd()+1;
			printf("%lld\n",query3(1,1,n,l,r));
		}
		else{
			int l=rd()+1,r=rd()+1;
			printf("%lld\n",query4(1,1,n,l,r));
		}
	}
	return 0;
}
posted @   flywatre  阅读(31)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具
点击右上角即可分享
微信分享提示