bzoj 5028: 小Z的加油店——带修改的区间gcd
Description
小Z经营一家加油店。小Z加油的方式非常奇怪。他有一排瓶子,每个瓶子有一个容量vi。每次别人来加油,他会让
别人选连续一段的瓶子。他可以用这些瓶子装汽油,但他只有三种操作:
1.把一个瓶子完全加满;
2.把一个瓶子完全倒空;
3.把一个瓶子里的汽油倒进另一个瓶子,直到倒出瓶子空了或者倒进的瓶子满了。
当然,为了回馈用户,小Z会时不时选择连续一段瓶子,给每个瓶子容积都增加x。
为了尽可能给更多的人加油,每次客户来加油他都想知道他能够倒腾出的汽油量最少是多少?
当然他不会一点汽油都不给客户。
Input
第一行包括两个数字:瓶子数n,事件数m。
第二行包含n个整数,表示每个瓶子的容量vi。
接下来m行,每行先有三个整数fi li ri。
若fi=1表示询问li到ri他最少能倒腾出的汽油量最少是多少?
若fi=2 再读入一个整数x。表示他将li到ri的瓶子容量都增加了x。
1 <= n,m <= 10^5 , 1<=li<=ri<=n , 1<=初始容量,增加的容量<=1000
Output
对于每个询问输出对应的答案
Sample Input
3 4
2 3 4
1 1 3
2 2 2 1
1 1 3
1 2 3
2 3 4
1 1 3
2 2 2 1
1 1 3
1 2 3
Sample Output
1
2
4
2
4
HINT
有可能出现L>R
——————————————————————————————
考虑一下更相减损术 题目就转换成了求区间gcd(带修改
这是一波套路题 考虑gcd(a,b,c,d,e)=gcd(a-b,b-c,c-d,d-e,e)
所以我们可以维护一下差分 也就是类似a-b这样的东西
这样之后区间l->r +v 就变成了 l-1 - v r +v
当然注意最后的e是不带差分的 所以还要维护一下原序列 方便查询右端点r
所以需要的操作就是 维护原序列的差分(单点修改区间查gcd)和原序列本身(区间加单点查询)
#include<cstdio> #include<cstring> #include<algorithm> const int M=1e5+7; int read(){ int ans=0,f=1,c=getchar(); while(c<'0'||c>'9'){if(c=='-') f=-1; c=getchar();} while(c>='0'&&c<='9'){ans=ans*10+(c-'0'); c=getchar();} return ans*f; } int n,m,p; int N,g[3*M],bit[M],h[M]; int gcd(int x,int y){ while(y){p=x%y; x=y; y=p;} return x; } void tr_modify(int x,int v){ g[x+=N]+=v; for(x>>=1;x;x>>=1) g[x]=gcd(g[x<<1],g[x<<1^1]); } #define lowbit(x) x&-x int s[M]; void bit_insert(int x,int v){ while(x<=n){ s[x]+=v; x+=lowbit(x); } } int bit_query(int x){ int ans=h[x]; while(x) ans+=s[x],x-=lowbit(x); return ans; } void modify(int l,int r,int v){ bit_insert(l,v); tr_modify(l-1,-v); bit_insert(r+1,-v); tr_modify(r,v); } int push_ans(int l,int r){ int ans=bit_query(r); for(l=l+N-1,r=r+N;r-l!=1;l>>=1,r>>=1){ if(~l&1) ans=gcd(ans,g[l^1]); if(r&1) ans=gcd(ans,g[r^1]); } if(ans<0) ans=-ans; return ans; } void pd(int &x,int &y){if(x>y) std::swap(x,y);} int main(){ int k,l,r,v; n=read(); m=read(); for(int i=1;i<=n;i++) h[i]=read(); for(N=1;N<=n+5;N<<=1); for(int i=1;i<n;i++) g[i+N]=h[i]-h[i+1]; for(int i=N-1;i;i--) g[i]=gcd(g[i<<1],g[i<<1^1]); for(int i=1;i<=m;i++){ k=read(); if(k==1) l=read(),r=read(),pd(l,r),printf("%d\n",push_ans(l,r)); else l=read(),r=read(),v=read(),pd(l,r),modify(l,r,v); } return 0; }