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
",querymn(1,1,n));
    if(op==4) printf("%lld
",query(1,1,n));
  } 
}
} signed main() {Luitaryi::main(); return 0;}

2019.08.30
70

原文地址:https://www.cnblogs.com/Jackpei/p/11437556.html