HDU - 5828 Rikka with Sequence (线段树)
三种操作:区间加,区间开根号,区间求和。
修改的时候判断区间内的最大值和最小值是否相等或者差1,如果相等则变为区间赋值,否则再判断开根号之后的最大值和最小值是否相等,如果相等则区间赋值,否则区间加法。
这题的数据也忒恶心了点吧?本来直接判断相等就能解决的问题,非要加上一个玄学的优化才能过掉...
1 #include<bits/stdc++.h> 2 using namespace std; 3 typedef long long ll; 4 const int N=1e5+10,inf=0x3f3f3f3f; 5 int n,m,a[N]; 6 ll sum[N<<2],mx[N<<2],mi[N<<2],ad[N<<2],st[N<<2]; 7 #define ls (u<<1) 8 #define rs (u<<1|1) 9 #define mid ((l+r)>>1) 10 void add(int u,ll x,int l,int r) {sum[u]+=x*(r-l+1),mx[u]+=x,mi[u]+=x,ad[u]+=x;} 11 void Set(int u,ll x,int l,int r) {sum[u]=x*(r-l+1),mx[u]=mi[u]=x,ad[u]=0,st[u]=x;} 12 void pu(int u) {sum[u]=sum[ls]+sum[rs],mx[u]=max(mx[ls],mx[rs]),mi[u]=min(mi[ls],mi[rs]);} 13 void pd(int u,int l,int r) { 14 if(~st[u])Set(ls,st[u],l,mid),Set(rs,st[u],mid+1,r),st[u]=-1; 15 if(ad[u])add(ls,ad[u],l,mid),add(rs,ad[u],mid+1,r),ad[u]=0; 16 } 17 void build(int u=1,int l=1,int r=n) { 18 ad[u]=0,st[u]=-1; 19 if(l==r) {sum[u]=mx[u]=mi[u]=a[l]; return;} 20 build(ls,l,mid),build(rs,mid+1,r),pu(u); 21 } 22 void upd1(int L,int R,ll x,int u=1,int l=1,int r=n) { 23 if(l>=L&&r<=R) {add(u,x,l,r); return;} 24 if(l>R||r<L)return; 25 pd(u,l,r),upd1(L,R,x,ls,l,mid),upd1(L,R,x,rs,mid+1,r),pu(u); 26 } 27 void upd2(int L,int R,int u=1,int l=1,int r=n) { 28 if(l>=L&&r<=R&&mx[u]-mi[u]<=1) { 29 if((ll)sqrt(mx[u]+0.5)==(ll)sqrt(mi[u]+0.5))Set(u,(ll)sqrt(mx[u]+0.5),l,r); 30 else add(u,(ll)sqrt(mx[u]+0.5)-mx[u],l,r); 31 return; 32 } 33 if(l>R||r<L)return; 34 pd(u,l,r),upd2(L,R,ls,l,mid),upd2(L,R,rs,mid+1,r),pu(u); 35 } 36 ll qry(int L,int R,int u=1,int l=1,int r=n) { 37 if(l>=L&&r<=R)return sum[u]; 38 if(l>R||r<L)return 0; 39 pd(u,l,r); 40 return qry(L,R,ls,l,mid)+qry(L,R,rs,mid+1,r); 41 } 42 int main() { 43 int T; 44 for(scanf("%d",&T); T--;) { 45 scanf("%d%d",&n,&m); 46 for(int i=1; i<=n; ++i)scanf("%d",&a[i]); 47 build(); 48 while(m--) { 49 int f,l,r,x; 50 scanf("%d%d%d",&f,&l,&r); 51 if(f==1)scanf("%d",&x); 52 if(f==1)upd1(l,r,x); 53 else if(f==2)upd2(l,r); 54 else if(f==3)printf("%lld\n",qry(l,r)); 55 } 56 } 57 return 0; 58 }