LOJ 6029. 「雅礼集训 2017 Day1」市场
思路:线段树+转化
提交:2次
错因:由于智障没有判断左右端点ORZ
题解:
主要是如何把区间除下取整转化成更适合线段树的一些操作。
给定除数 \(d\) ,对于一段区间,若区间只包含 \(k*d\) 与 \(k*d-1\) ,我们可以转化成区间减,因为此时做完除法,新的数与原数的差相等,即
\[k*d-(k*d)/d=k*d-1-(k*d-1)/d
\]
\[k*d-k=k*d-1-(k-1)
\]
所以我们就把区间除变成了区间减辣!(但是复杂度玄学)
代码:
#include<cstdio>
#include<iostream>
#include<cmath>
#define R register int
#define ll long long
using namespace std;
namespace Luitaryi {
static char B[1<<15],*S=B,*T=B;
#define getchar() (S==T&&(T=(S=B)+fread(B,1,1<<15,stdin),S==T)?EOF:*S++)
template<class I> inline I g(I& x) { x=0; register I f=1;
register char ch; while(!isdigit(ch=getchar())) f=ch=='-'?-1:f;
do x=x*10+(ch^48); while(isdigit(ch=getchar())); return x*=f;
} const int N=1e5+10; const ll Inf=1e+15;
int n,m,LL,RR,d;
ll mx[N<<2],mn[N<<2],sum[N<<2],tg[N<<2];
#define ls (tr<<1)
#define rs (tr<<1|1)
inline void upd(R tr) {
sum[tr]=sum[ls]+sum[rs];
mx[tr]=max(mx[ls],mx[rs]);
mn[tr]=min(mn[ls],mn[rs]);
}
inline void build(R tr,R l,R r) {
if(l==r) {sum[tr]=mn[tr]=g(mx[tr]); return ;} R md=l+r>>1;
build(ls,l,md),build(rs,md+1,r); upd(tr);
}
inline void spread(R tr,R l,R r,R md) { if(tg[tr]==0) return;
sum[ls]+=tg[tr]*(md-l+1),sum[rs]+=tg[tr]*(r-md);
mn[ls]+=tg[tr],mx[ls]+=tg[tr],mn[rs]+=tg[tr],mx[rs]+=tg[tr];
tg[ls]+=tg[tr],tg[rs]+=tg[tr]; tg[tr]=0;
}
inline void add(R tr,R l,R r) {
if(LL<=l&&r<=RR) {sum[tr]+=(r-l+1)*d,mx[tr]+=d,mn[tr]+=d,tg[tr]+=d; return ;}
R md=l+r>>1; spread(tr,l,r,md); if(LL<=md) add(ls,l,md);
if(RR>md) add(rs,md+1,r); upd(tr);
}
inline void div(R tr,R l,R r) {
if(LL<=l&&r<=RR) if((mx[tr]==mn[tr]||(mx[tr]==mn[tr]+1&&mx[tr]%d==0))) {
R c=mx[tr]-floor(1.0*mx[tr]/d);
sum[tr]-=(r-l+1)*c; mx[tr]-=c,mn[tr]-=c,tg[tr]-=c; return ;
} R md=l+r>>1; spread(tr,l,r,md);
if(LL<=md) div(ls,l,md); if(RR>md) div(rs,md+1,r); upd(tr);
}
inline ll querymn(R tr,R l,R r) {
if(LL<=l&&r<=RR) return mn[tr]; R md=l+r>>1; spread(tr,l,r,md);
register ll ret=Inf; if(LL<=md) ret=min(ret,querymn(ls,l,md));
if(RR>md) ret=min(ret,querymn(rs,md+1,r)); return ret;
}
inline ll query(R tr,R l,R r) {
if(LL<=l&&r<=RR) return sum[tr]; R md=l+r>>1; spread(tr,l,r,md);
register ll ret=0; if(LL<=md) ret+=query(ls,l,md);
if(RR>md) ret+=query(rs,md+1,r); return ret;
}
inline void main() {
g(n),g(m); build(1,1,n);
R op; while(m--) {
g(op),g(LL),g(RR),++LL,++RR;
if(op==1) g(d),add(1,1,n);
if(op==2) g(d),div(1,1,n);
if(op==3) printf("%lld\n",querymn(1,1,n));
if(op==4) printf("%lld\n",query(1,1,n));
}
}
} signed main() {Luitaryi::main(); return 0;}
2019.08.30
70