「雅礼集训 2017 Day1」市场(线段树维护区间除)

这里是引用
输入
第一行为两个空格隔开的整数 n,q 分别表示商贩个数和政令 + 询问个数。
第二行包含 n 个由空格隔开的整数 a0∼an−1
接下来 q 行,每行表示一个操作,第一个数表示操作编号 1∼4 ,接下来的输入和问题描述一致。
输出
对于每个 3、4 操作,输出询问答案。
样例输入
10 10
-5 -4 -3 -2 -1 0 1 2 3 4
1 0 4 1
1 5 9 1
2 0 9 3
3 0 9
4 0 9
3 0 1
4 2 3
3 4 5
4 6 7
3 8 9
样例输出
-2
-2
-2
-2
0
1
1
提示
数据范围与提示
对于 30%的数据,n,q≤10^3;
对于 60% 的数据,保证数据随机;
对于 100%的数据,1≤n,q≤10^5,0≤l≤r≤n−1, c∈[−10^4, 10^4], d∈[2,10^9]

其实这里的区间除操作挺简单的

类似于线段树的区间开方操作

因为这里只有区间加

所以整个数列最大的增加数也只有1e91e9左右(由于初始值好像好多都超过了intint范围所以不开longlonglong long还是要爆intint

由于区间除的区间的数每次至少减少一半,所以要不了log(ai)log(a_i)次整个区间的数就都变为11

而且又只有区间加,还是可以做到loglog次就变成11

当然如果每次真的强行nlognnlog_n强行每个数都除O(nlogn2nlog_{n^2})加上常数还是够呛

所以我们类似于开方

维护一个区间maxmaxminmin

max/k=min/kmax/k=min/k时,区间除就相当于整个区间减去了一个maximaxi/kmax_i-max_i/k

所以我们打一个减的标记就可以了

当然如果有区间乘就没法做了

注意有负数,还有序列是从11~n1n-1给出来的

代码

#include<bits/stdc++.h>
using namespace std;
#define int long long
inline int read(){
	char ch=getchar();
	int res=0,f=1;
	while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
	while(isdigit(ch))res=(res<<3)+(res<<1)+(ch^48),ch=getchar();
	return res*f;
}
#define lc (u<<1)
#define rc ((u<<1)|1)
#define mid ((l+r)>>1)
const int N=100005;
int n,m,a[N],mx[N<<2],mn[N<<2],sum[N<<2],add[N<<2];
inline int down(int x,int y) {
    return floor((double)x/y);
}
inline void pushup(int u){
	sum[u]=sum[lc]+sum[rc];
	mx[u]=max(mx[lc],mx[rc]);
	mn[u]=min(mn[lc],mn[rc]);
}
inline void pushdown(int u,int l,int r){
	if(!add[u])return;
	mx[lc]+=add[u],mx[rc]+=add[u];
	mn[lc]+=add[u],mn[rc]+=add[u];
	add[lc]+=add[u],add[rc]+=add[u];
	sum[lc]+=(mid-l+1)*add[u],sum[rc]+=(r-mid)*add[u];
	add[u]=0;
}
inline void buildtree(int u,int l,int r){
	if(l==r){
		mx[u]=mn[u]=sum[u]=a[l];return;
	}
	buildtree(lc,l,mid);
	buildtree(rc,mid+1,r);
	pushup(u);
}
inline void update(int u,int l,int r,int st,int des,int k){
	if(st<=l&&r<=des){
		add[u]+=k,sum[u]+=(r-l+1)*k,mx[u]+=k,mn[u]+=k;return;
	}
	pushdown(u,l,r);
	if(mid>=st)update(lc,l,mid,st,des,k);
	if(mid<des)update(rc,mid+1,r,st,des,k);
	pushup(u);
}
inline void updatec(int u,int l,int r,int st,int des,int k){
	if(st<=l&&r<=des&&((mx[u]-down(mx[u],k))==(mn[u]-down(mn[u],k)))){
		int del=down(mx[u],k)-mx[u];
		add[u]+=del,sum[u]+=(r-l+1)*del,mx[u]+=del,mn[u]+=del;return;
	}
	pushdown(u,l,r);
	if(mid>=st)updatec(lc,l,mid,st,des,k);
	if(mid<des)updatec(rc,mid+1,r,st,des,k);
	pushup(u);
}
inline int query(int u,int l,int r,int st,int des){
	if(st<=l&&r<=des){
		return mn[u];
	}
	int ans=1e18;
	pushdown(u,l,r);
	if(mid>=st)ans=min(ans,query(lc,l,mid,st,des));
	if(mid<des)ans=min(ans,query(rc,mid+1,r,st,des));
	pushup(u);
	return ans;
}
inline int queryt(int u,int l,int r,int st,int des){
	if(st<=l&&r<=des){
		return sum[u];
	}
	int ans=0;
	pushdown(u,l,r);
	if(mid>=st)ans+=queryt(lc,l,mid,st,des);
	if(mid<des)ans+=queryt(rc,mid+1,r,st,des);
	pushup(u);
	return ans;
}
signed main(){
	n=read(),m=read();
	for(int i=1;i<=n;i++)a[i]=read();
	buildtree(1,1,n);
	for(int i=1;i<=m;i++){
		int op=read();
		if(op==1){
			int l=read()+1,r=read()+1,c=read();
			update(1,1,n,l,r,c);
		}
		else if(op==2){
			int l=read()+1,r=read()+1,k=read();
			updatec(1,1,n,l,r,k);
		}
		else if(op==3){
			int l=read()+1,r=read()+1;
			cout<<query(1,1,n,l,r)<<'\n';
		}
		else if(op==4){
			int l=read()+1,r=read()+1;
			cout<<queryt(1,1,n,l,r)<<'\n';
		}
	}
}
posted @ 2019-01-04 20:45  Stargazer_cykoi  阅读(128)  评论(0编辑  收藏  举报