小阳的贝壳
小阳的贝壳
https://ac.nowcoder.com/acm/problem/26255
题意:
有n个有颜色的贝壳,每一个的颜色值为col[i],小阳能进行以下三种操作:
1 l r x:给 [l,r]区间里所有贝壳的颜色值加上x。
2 l r:询问 [l,r]区间里所有相邻贝壳颜色值的差(取绝对值)的最大值(若l=r输出0)。
3 l r :询问 [l,r]区间里所有贝壳颜色值的最大公约数。
思路:
先构造一个差分数组,根据差分数组构造线段树,维护区间值的和、区间值绝对值的最大值、区间值的最大公约数(gcd是具有区间可维护性的,即gcd(a,b,c,d) = gcd(gcd(a,b),gcd(c,d))).
操作一:在线段树中更新(l-1)的位置加x,r的位置加(-x)。
操作二:在线段树中询问[l,r-1]区间的绝对值的最大值。
操作三:在线段树中询问[l,r-1]区间的绝对值的最大公约数,以及[1,l-1]区间的区间值的和。(gcd(a,b,c,d)=gcd(a,b-a,c-b,d-c),即[l,r]区间里所有贝壳颜色值的最大公约数为gcd(a[l],[l-r-1]区间的绝对值的最大公约数),a[l]=a[1]+[1,l-1]区间的区间值的和.)
代码:
#include<bits/stdc++.h> #include<iostream> #include<cstdio> #include<algorithm> #include<cstring> #include<queue> using namespace std; typedef long long ll; int n, m, a[100005], b[100005]; struct w { int m, g, v; }w[400005]; void build(int p,int l,int r) { if(l==r) { w[p].v=b[l]; w[p].g=abs(b[l]); w[p].m=abs(b[l]); return ; } else if(l>r) { return ; } int mid=(l+r)/2; build(p*2,l,mid); build(p*2+1,mid+1,r); w[p].g=__gcd(w[p*2].g,w[p*2+1].g); w[p].m=max(w[p*2].m,w[p*2+1].m); w[p].v=w[p*2].v+w[p*2+1].v; } void change(int p,int l,int r,int x,int v) { if(l==r&&l==x) { w[p].v+=v; w[p].m=abs(w[p].v); w[p].g=abs(w[p].v); return ; } int mid=(l+r)/2; if(mid>=x) { change(p*2,l,mid,x,v); } else { change(p*2+1,mid+1,r,x,v); } w[p].g=__gcd(w[p*2].g,w[p*2+1].g); w[p].m=max(w[p*2].m,w[p*2+1].m); w[p].v=w[p*2].v+w[p*2+1].v; } int ask(int p,int l,int r,int x,int y) { if(l>r||x>y) { return 0; } if(x<=l&&r<=y) { return w[p].m; } int mid=(l+r)/2; if(x>mid) { return ask(p*2+1,mid+1,r,x,y); } if(y<=mid) { return ask(p*2,l,mid,x,y); } return max(ask(p*2,l,mid,x,mid),ask(p*2+1,mid+1,r,mid+1,y)); } int ask1(int p,int l,int r,int x,int y) { if(l>r||x>y) { return 0; } if(x<=l&&r<=y) { return w[p].v; } int mid=(l+r)/2; if(x>mid) { return ask1(p*2+1,mid+1,r,x,y); } if(y<=mid) { return ask1(p*2,l,mid,x,y); } return ask1(p*2,l,mid,x,mid)+ask1(p*2+1,mid+1,r,mid+1,y); } int ask2(int p,int l,int r,int x,int y) { if(l>r||x>y) { return 0; } if(x<=l&&r<=y) { return w[p].g; } int mid=(l+r)/2; if(x>mid) { return ask2(p*2+1,mid+1,r,x,y); } if(y<=mid) { return ask2(p*2,l,mid,x,y); } return __gcd(ask2(p*2,l,mid,x,mid),ask2(p*2+1,mid+1,r,mid+1,y)); } int main() { scanf("%d%d",&n,&m); for(int i=1;i<=n;i++) { scanf("%d",&a[i]); } for(int i=1;i<=n-1;i++) { b[i]=a[i+1]-a[i]; } build(1,1,n-1); while(m--) { int k; scanf("%d",&k); if(k==1) { int l, r, x; scanf("%d%d%d",&l,&r,&x); if(l==1) { a[1]+=x; } else { change(1,1,n-1,l-1,x); } if(r==n) { ; } else { change(1,1,n-1,r,-x); } } else if(k==2) { int l, r; scanf("%d%d",&l,&r); if(l==r) { printf("0\n"); } else { printf("%d\n",ask(1,1,n-1,l,r-1)); } } else { int l, r; scanf("%d%d",&l,&r); printf("%d\n",__gcd((a[1]+ask1(1,1,n-1,1,l-1)),ask2(1,1,n-1,l,r-1))); } } return 0; }
每日一题题解 文章被收录于专栏
写题解