#6029. 「雅礼集训 2017 Day1」市场
题目描述
从前有一个贸易市场,在一位执政官到来之前都是非常繁荣的,自从他来了之后,发布了一系列奇怪的政令,导致贸易市场的衰落。
有 n nn 个商贩,从 0∼n−1 0 sim n - 10∼n−1 编号,每个商贩的商品有一个价格 ai a_iai,有两种政令:
- l,r,c l, r, cl,r,c,对于 i∈[l,r],ai←ai+c i in [l, r], a_i leftarrow a_i + ci∈[l,r],ai←ai+c
- l,r,d l, r, dl,r,d,对于 i∈[l,r],ai←⌊ai/d⌋ i in [l, r], a_i leftarrow lfloor {a_i}/{d} floori∈[l,r],ai←⌊ai/d⌋
现在有一个外乡的旅客想要了解贸易市场的信息,有两种询问方式:
- 给定 l,r l, rl,r,求 mini∈[l,r]ai min_{i in [l, r]} a_imini∈[l,r]ai
- 给定 l,r l, rl,r,求 ∑i∈[l,r]ai sum_{iin [l, r]} a_i∑i∈[l,r]ai
输入格式
第一行为两个空格隔开的整数 n,q n, qn,q 分别表示商贩个数和政令 + 询问个数。
第二行包含 n nn 个由空格隔开的整数 a0∼an−1 a_0 sim a_{n - 1}a0∼an−1
接下来 q qq 行,每行表示一个操作,第一个数表示操作编号 1∼4 1 sim 41∼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% 30\%30% 的数据,n,q≤103 n, q leq 10 ^ 3n,q≤103;
对于 60% 60\%60% 的数据,保证数据随机;
对于 100% 100\%100% 的数据,1≤n,q≤105,0≤l≤r≤n−1,c∈[−104,104],d∈[2,109] 1 leq n, q leq 10 ^ 5, 0 leq l leq r leq n - 1, c in [-10 ^ {4}, 10 ^ 4], d in [2, 10 ^ 9]1≤n,q≤105,0≤l≤r≤n−1,c∈[−104,104],d∈[2,109]
区间除用到了分块除法,可以转化为区间加法(复杂度玄学)
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include<iostream> #include<cstdio> #include<cstring> #include<cmath> #define maxn 100010 using namespace std; int n,m; long long sum[maxn*10],a[maxn],mn[maxn*10]; long long qread(){ int i=0,j=1; char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')j=-1;ch=getchar();} while(ch<='9'&&ch>='0'){i=i*10+ch-'0';ch=getchar();} return i*j; } void build(int k,int l,int r){ if(l==r){ mn[k]=sum[k]=a[l]; return; } int mid=(l+r)>>1; build(k<<1,l,mid); build(k<<1|1,mid+1,r); sum[k]=sum[k<<1]+sum[k<<1|1]; mn[k]=min(mn[k<<1],mn[k<<1|1]); } void modify(int k,int l,int r,int opx,int opv){ if(l==r){ mn[k]=sum[k]=opv; return; } int mid=(l+r)>>1; if(opx<=mid)modify(k<<1,l,mid,opx,opv); else modify(k<<1|1,mid+1,r,opx,opv); mn[k]=min(mn[k<<1],mn[k<<1|1]); sum[k]=sum[k<<1]+sum[k<<1|1]; } long long querymn(int k,int l,int r,int opl,int opr){ if(l>=opl&&r<=opr){return mn[k];} int mid=(l+r)>>1; long long res=1000000000000; if(opl<=mid)res=min(res,querymn(k<<1,l,mid,opl,opr)); if(opr>mid)res=min(res,querymn(k<<1|1,mid+1,r,opl,opr)); return res; } long long querysum(int k,int l,int r,int opl,int opr){ if(l>=opl&&r<=opr){return sum[k];} int mid=(l+r)>>1; long long res=0; if(opl<=mid)res+=querysum(k<<1,l,mid,opl,opr); if(opr>mid)res+=querysum(k<<1|1,mid+1,r,opl,opr); return res; } int main(){ scanf("%d%d",&n,&m); for(int i=1;i<=n;i++)a[i]=qread(); build(1,1,n); int op,l,r,v; for(int i=1;i<=m;i++){ scanf("%d",&op); if(op==1){ scanf("%d%d%d",&l,&r,&v);l++;r++; for(int j=l;j<=r;j++){ a[j]=a[j]+v; modify(1,1,n,j,a[j]); } } if(op==2){ scanf("%d%d%d",&l,&r,&v);l++;r++; for(int j=l;j<=r;j++){ a[j]=floor((double)a[j]/(double)v); modify(1,1,n,j,a[j]); } } if(op==3){ scanf("%d%d",&l,&r);l++;r++; printf("%lld ",querymn(1,1,n,l,r)); } if(op==4){ scanf("%d%d",&l,&r);l++;r++; printf("%lld ",querysum(1,1,n,l,r)); } } return 0; }
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #define maxn 100010 #define INF 1000000000 using namespace std; long long sum[maxn*4],maxs[maxn*4],mins[maxn*4],lazy[maxn*4]; int num[maxn*4]; void pushup(int k){ sum[k]=sum[k<<1]+sum[k<<1|1]; mins[k]=min(mins[k<<1],mins[k<<1|1]); maxs[k]=max(maxs[k<<1],maxs[k<<1|1]); } void pushlazy(int k,int lz,int len){ mins[k]+=lz; maxs[k]+=lz; sum[k]+=lz*len; lazy[k]+=lz; } void pushdown(int l,int r,int k){ if(lazy[k]!=0){ int mid=(l+r)>>1; pushlazy(k<<1,lazy[k],mid-l+1); pushlazy(k<<1|1,lazy[k],r-mid); lazy[k]=0; } return; } void build(int l,int r,int k){ if(l==r){ sum[k]=mins[k]=maxs[k]=num[l]; return; } int mid=(l+r)>>1; build(l,mid,k<<1);build(mid+1,r,k<<1|1); pushup(k); } void modify(int v,int l,int r,int opl,int opr,int k){ if(l>=opl&&r<=opr){ lazy[k]+=v; sum[k]+=v*(r-l+1); mins[k]+=v; maxs[k]+=v; return; } pushdown(l,r,k); int mid=(l+r)>>1; if(opl<=mid)modify(v,l,mid,opl,opr,k<<1); if(opr>mid)modify(v,mid+1,r,opl,opr,k<<1|1); pushup(k); } void div(int v,int l,int r,int opl,int opr,int k){ if(l>=opl&&r<=opr){ long long A,B; if(mins[k]<0)A=(mins[k]-v+1)/v; else A=mins[k]/v; if(maxs[k]<0)B=(maxs[k]-v+1)/v; else B=maxs[k]/v; if(A-mins[k]==B-maxs[k]){ pushlazy(k,A-mins[k],r-l+1); return; } } pushdown(l,r,k); int mid=(l+r)>>1; if(opl<=mid)div(v,l,mid,opl,opr,k<<1); if(opr>mid)div(v,mid+1,r,opl,opr,k<<1|1); pushup(k); } long long querysum(int opl,int opr,int l,int r,int k){ if(l>=opl&&r<=opr)return sum[k]; pushdown(l,r,k); int mid=(l+r)>>1; long long ans=0; if(opl<=mid)ans+=querysum(opl,opr,l,mid,k<<1); if(opr>mid)ans+=querysum(opl,opr,mid+1,r,k<<1|1); return ans; } long long querymn(int opl,int opr,int l,int r,int k){ if(l>=opl&&r<=opr)return mins[k]; pushdown(l,r,k); int mid=(l+r)>>1; long long ans=INF; if(opl<=mid)ans=min(ans,querymn(opl,opr,l,mid,k<<1)); if(opr>mid)ans=min(ans,querymn(opl,opr,mid+1,r,k<<1|1)); return ans; } int main(){ int n,m; scanf("%d%d",&n,&m); for(int i=1;i<=n;i++)scanf("%d",&num[i]); build(1,n,1); int op,l,r,v; for(int i=1;i<=m;i++){ scanf("%d",&op); if(op==1){ scanf("%d%d%d",&l,&r,&v); modify(v,1,n,l+1,r+1,1); } if(op==2){ scanf("%d%d%d",&l,&r,&v); div(v,1,n,l+1,r+1,1); } if(op==3){ scanf("%d%d",&l,&r); printf("%lld ",querymn(l+1,r+1,1,n,1)); } if(op==4){ scanf("%d%d",&l,&r); printf("%lld ",querysum(l+1,r+1,1,n,1)); } } return 0; }