【loj6029】「雅礼集训 2017 Day1」市场

题目

题意:四种操作,区间加法、区间除法(下取整)、区间求最小值、区间求和。

第1、3、4个操作都是摆设,关键在于如何做区间除法。

很明显不能直接把区间的和做除法后向下取整,因为区间和可能会多凑出一个除数因子。例如$3,3$,对这两个数的区间除以2取整后变成$1,1$,但如果直接把它们的和6除以2取整后得到的和是3,很明显有误。

但是根据经验,带有区间除法操作的题目一般都会把数给你往小了压。再一看这题,两个修改操作中,区间加法的加数不大且可能是负数,而除数可高达$10^9$!

尤其是除法的大除数带来的影响特别大,这实际上暗示我们序列的数很容易迅速被压到0附近。而数的绝对值被压倒很小,除数却有很大时,我们发现实际上这些数的变化可能会很小。小到什么程度呢?

考虑如果有一些近似连续的小数段,

比如$2,2,2,3,3,3$,在除3意义下,变成$0,0,0,1,1,1$,相当于整体-2。

在序列的数都被压到足够接近0时,很容易出现上面这种序列,此时就可以用区间加法维护上面这种区间的除法操作了!

那怎么判断除法区间的所有数的变化量是否相同呢?只需判断最大值和最小值的变化量是否相同即可。简单原因:除法区间的数按从小到大的顺序,数的变化量是单调不下降的(废特么话…大数和小数都被同一个除数除,大数当然还比小数大,即使是在向下取整的意义下也不会比小数小),所以只要看两端的最小值和最大值的变化量是否相同就能知道整个区间的数的变化量是否相同。

归根结底区间除法转化成了区间加法+区间最大值+区间最小值,于是还需要维护一下原题没有要求的区间最大值。

扫描二维码关注公众号,回复: 3141683 查看本文章
  1 #include<bits/stdc++.h>
  2 #define N 100001
  3 #define inf 0x7f7f7f7f7f7f7f7f
  4 using namespace std;
  5 inline int read(){
  6     int x=0; bool f=1; char c=getchar();
  7     for(;!isdigit(c);c=getchar()) if(c=='-') f=0;
  8     for(; isdigit(c);c=getchar()) x=(x<<3)+(x<<1)+(c^'0');
  9     if(f) return x;
 10     return 0-x;
 11 }
 12 int n,q;
 13 long long a[N],mx[N<<2],mn[N<<2],sum[N<<2],tag[N<<2];
 14 int L,R,x;
 15 inline void pushup(int o){
 16     sum[o]=sum[o<<1]+sum[o<<1|1];
 17     mx[o]=max(mx[o<<1],mx[o<<1|1]);
 18     mn[o]=min(mn[o<<1],mn[o<<1|1]);
 19 }
 20 void pushdown(int o,int l,int r){
 21     if(!tag[o] || l==r) return;
 22     //printf("pushdown:%d %d %d %d %d\n",o,l,r,tag[o],mn[o]);
 23     int mid=(l+r)>>1;
 24     sum[o<<1]+=(mid-l+1)*tag[o], sum[o<<1|1]+=(r-mid)*tag[o];
 25     mx[o<<1]+=tag[o], mx[o<<1|1]+=tag[o];
 26     mn[o<<1]+=tag[o], mn[o<<1|1]+=tag[o];
 27     tag[o<<1]+=tag[o], tag[o<<1|1]+=tag[o]; //严重错因,好几个小时才查出这里直接覆盖儿子tag值的错误,一定要铭记!
 28     tag[o]=0;
 29 }
 30 void build(int o,int l,int r){
 31     //printf("%d %d %d\n",o,l,r); system("pause");
 32     if(l==r){sum[o]=mx[o]=mn[o]=a[l]; return;}
 33     int mid=(l+r)>>1;
 34     build(o<<1,l,mid), build(o<<1|1,mid+1,r);
 35     pushup(o);
 36 }
 37 void add(int o,int l,int r){
 38     //printf("query:%d %d %d %d\n",l,r,mn[o],tag[o]);
 39     if(L<=l && r<=R){
 40         tag[o]+=x, sum[o]+=(long long)(r-l+1)*x, mx[o]+=x, mn[o]+=x;
 41         return;
 42     }
 43     pushdown(o,l,r);
 44     int mid=(l+r)>>1;
 45     if(L<=mid) add(o<<1,l,mid);
 46     if(mid<R) add(o<<1|1,mid+1,r);
 47     pushup(o);//printf("pushup hou:%d %d %d %d %d\n",l,r,mn[o],mn[o<<1],mn[o<<1|1]);
 48 }
 49 long long min_query(int o,int l,int r){
 50     //printf("query:%d %d %d %d\n",l,r,mn[o],tag[o]);
 51     if(L<=l && r<=R) return mn[o];
 52     pushdown(o,l,r);
 53     int mid=(l+r)>>1;
 54     long long ret=inf;
 55     if(L<=mid) ret=min(ret,min_query(o<<1,l,mid));
 56     if(mid<R) ret=min(ret,min_query(o<<1|1,mid+1,r));
 57     pushup(o);
 58     return ret;
 59 }
 60 void div(int o,int l,int r){
 61     //printf("query:%d %d %d %d\n",l,r,mn[o],tag[o]);
 62     if(L<=l && r<=R){
 63         long long g1=mx[o]-(long long)floor((double)mx[o]/x), g2=mn[o]-(long long)floor((double)mn[o]/x);
 64         if(g1==g2){
 65             //printf("fvcking subquence:%d %d %lld %lld\n",l,r,g1,g2);
 66             tag[o]-=g1, sum[o]-=(r-l+1)*g1, mx[o]-=g1, mn[o]-=g1;
 67             return;
 68         }
 69     }
 70     pushdown(o,l,r);
 71     int mid=(l+r)>>1;
 72     if(L<=mid) div(o<<1,l,mid);
 73     if(mid<R) div(o<<1|1,mid+1,r);
 74     pushup(o);
 75 }
 76 long long sum_query(int o,int l,int r){
 77     //printf("query:%d %d %d %d\n",l,r,mn[o],tag[o]);
 78     if(L<=l && r<=R) return sum[o];
 79     pushdown(o,l,r);
 80     int mid=(l+r)>>1;
 81     long long ret=0;
 82     if(L<=mid) ret+=sum_query(o<<1,l,mid);
 83     if(mid<R) ret+=sum_query(o<<1|1,mid+1,r);
 84     pushup(o);
 85     return ret;
 86 }
 87 
 88 void find(int o,int l,int r){
 89     if(l==r){printf("%d ",sum[o]); return;}
 90     pushdown(o,l,r);
 91     int mid=(l+r)>>1;
 92     find(o<<1,l,mid), find(o<<1|1,mid+1,r);
 93     pushup(o);
 94 }
 95 
 96 int main(){
 97     //freopen("rand.in","r",stdin);
 98     //freopen("count.out","w",stdout);
 99     n=read(),q=read();
100     int i,k;
101     for(i=1;i<=n;i++) a[i]=read();
102     build(1,1,n);
103     for(i=1;i<=q;i++){
104         k=read(),L=read()+1,R=read()+1;
105         if(k==1) x=read(), add(1,1,n);
106         else if(k==2) x=read(), div(1,1,n);
107         else if(k==3) printf("%lld\n",min_query(1,1,n));
108         else if(k==4) printf("%lld\n",sum_query(1,1,n));
109         //find(1,1,n);
110         //putchar('\n');putchar('\n');putchar('\n');putchar('\n');
111     }
112     return 0;
113 }
114 /*
115 10 11
116 1 2 3 4 5 6 7 8 9 10
117 2 0 9 2
118 2 0 9 3
119 2 0 9 4
120 2 0 9 5
121 2 0 9 6
122 3 0 9
123 4 0 9
124 1 0 4 -4
125 2 0 4 2
126 3 0 4
127 4 0 9
128 */
View Code

猜你喜欢

转载自www.cnblogs.com/scx2015noip-as-php/p/loj6029.html