赞
踩
题目链接
链接:https://ac.nowcoder.com/acm/contest/949/H
来源:牛客网
题目描述
小阳手中一共有 n 个贝壳,每个贝壳都有颜色,且初始第 i 个贝壳的颜色为coli。
现在小阳有 3 种操作:
1 l r x:给 [l,r] 区间里所有贝壳的颜色值加上 x 。
2 l r :询问 [l,r] 区间里所有相邻贝壳 颜色值的差(取绝对值) 的最大值(若 l=r输出0)
3 l r :询问 [l,r] 区间里所有贝壳颜色值的最大公约数。
题目要求3个操作分别是:
维护区间修改 ,维护区间最大公因数(GCD) ,维护相邻差值 的最大值
如何维护区间GCD ,有一下公式
gcd(a,b)=gcd(a,b−a)
gcd(a,b,c)=gcd(a,b−a,c−b)
gcd(a1,a2,⋯,an)=gcd(a1,a2−a1,a3−a2,⋯,an−an−1)
观察公式 a1, a2-a1,⋯,an−an−1 为 差分数列
不懂差分的看这差分性质
因此用 差分数列 建线段树
1. 区间修改 根据差分性质 变成了单点修改
2. 区间gcd 求[L,R]的 最大公因数, 分成求 [1,L] 差分数列的区间和sum 与 [L+1,R]的gcd
3. 差值最大值,直接维护差值绝对值的最大值
| | 双竖线 代表 绝对值 , 因为差分过程 可能会出现负数
1.gcd(a1,a2,⋯,an)=gcd(a1, | a2−a1 | , | a3−a2 | ,⋯, | an−an−1 | )
2.gcd(a1,a2,⋯,an)= | gcd(a1,a2−a1,a3−a2,⋯,an−an−1) |
//模板1 #include <iostream> #include <bits/stdc++.h> using namespace std; typedef long long ll; const int N=1e5+10; typedef struct { ll sum; // 维护差分数列前缀和 ll gcd; // 维护差分数列 最大公因数 ll mx; // 维护相邻差值的 最大值 }stu; stu tr[N<<2]; ll a[N],b[N]; /* gcd(a,b)=gcd(a,b−a) gcd(a,b,c)=gcd(a,b−a,c−b) gcd(a1,a2,⋯,an)=gcd(a1,a2−a1,a3−a2,⋯,an−an−1) */ void pushup(ll p) { tr[p].sum=tr[p<<1].sum+tr[p<<1|1].sum; tr[p].gcd=__gcd(tr[p<<1].gcd,tr[p<<1|1].gcd); // __gcd() 为c++ 自带最大公因数函数 tr[p].mx=max(tr[p<<1].mx,tr[p<<1|1].mx); } void build(ll p,ll l,ll r) { if(l==r) { tr[p].sum=b[l]; tr[p].gcd=abs(b[l]); tr[p].mx=abs(b[l]); return; } ll mid=(l+r)>>1; build(p<<1,l,mid); build(p<<1|1,mid+1,r); pushup(p); } void update(ll p,ll l,ll r,ll pos,ll x) { if(l==r) { tr[p].sum+=x; tr[p].gcd=abs(tr[p].sum); tr[p].mx=abs(tr[p].sum); return ; } ll mid=(l+r)>>1; if(pos<=mid) update(p<<1,l,mid,pos,x); if(pos>mid) update(p<<1|1,mid+1,r,pos,x); pushup(p); } ll query1(ll p,ll l,ll r,ll x,ll y) // 维护区间和 { ll ans=0; if(x<=l&&r<=y) { return tr[p].sum; } ll mid=(l+r)>>1; if(x<=mid) ans+=query1(p<<1,l,mid,x,y); if(y>mid) ans+=query1(p<<1|1,mid+1,r,x,y); return ans; } ll query2(ll p,ll l,ll r,ll x,ll y) // 查询 差值最大 { ll ans=0; if(x<=l&&r<=y) { return tr[p].mx; } ll mid=(l+r)>>1; if(x<=mid) ans=query2(p<<1,l,mid,x,y); if(y>mid) ans=max(ans,query2(p<<1|1,mid+1,r,x,y)); return ans; } ll query3(ll p,ll l,ll r,ll x,ll y) // 查询区间gcd { ll ans=0; if(x<=l&&r<=y) { return tr[p].gcd; } ll mid=(l+r)>>1; if(x<=mid) ans=query3(p<<1,l,mid,x,y); if(y>mid) ans=__gcd(ans,query3(p<<1|1,mid+1,r,x,y)); return ans; } int main() { int n,m; int opt; ll x,y,z; scanf("%d %d",&n,&m); for(int i=1;i<=n;i++) { scanf("%lld",&a[i]); b[i]=a[i]-a[i-1]; } build(1,1,n); ll ans,num; for(int i=1;i<=m;i++) { scanf("%d",&opt); if(opt==1) { scanf("%lld %lld %lld",&x,&y,&z); update(1,1,n,x,z); if(y+1<=n) update(1,1,n,y+1,-z); } else if(opt==2) { scanf("%lld %lld",&x,&y); if(x==y) { printf("0\n"); } else { ans=abs(query2(1,1,n,x+1,y)); printf("%lld\n",ans); } } else if(opt==3) { scanf("%lld %lld",&x,&y); num=query1(1,1,n,1,x); ans=__gcd(num,query3(1,1,n,x+1,y)); printf("%lld\n",ans); } } } return 0; }
//模板2 #include <iostream> #include <bits/stdc++.h> using namespace std; typedef long long ll; const int N=1e5+10; /* gcd(a,b)=gcd(a,b−a) gcd(a,b,c)=gcd(a,b−a,c−b) gcd(a1,a2,⋯,an)=gcd(a1,a2−a1,a3−a2,⋯,an−an−1) */ typedef struct { ll sum; // 维护差分数列前缀和 ll gcd; // 维护差分数列 最大公因数 ll mx; // 维护相邻差值的 最大值 }stu; stu tr[N<<2]; ll a[N],b[N]; void pushup(ll p) { tr[p].sum=tr[p<<1].sum+tr[p<<1|1].sum; tr[p].gcd=__gcd(tr[p<<1].gcd,tr[p<<1|1].gcd); tr[p].mx=max(tr[p<<1].mx,tr[p<<1|1].mx); } void build(ll p,ll l,ll r) { if(l==r) { tr[p].sum=b[l]; tr[p].gcd=b[l]; tr[p].mx=abs(b[l]); return; } ll mid=(l+r)>>1; build(p<<1,l,mid); build(p<<1|1,mid+1,r); pushup(p); } void update(ll p,ll l,ll r,ll pos,ll x) { if(l==r) { tr[p].sum+=x; tr[p].gcd+=x; tr[p].mx=abs(tr[p].sum); return ; } ll mid=(l+r)>>1; if(pos<=mid) update(p<<1,l,mid,pos,x); if(pos>mid) update(p<<1|1,mid+1,r,pos,x); pushup(p); } ll query1(ll p,ll l,ll r,ll x,ll y) // 维护区间和 { ll ans=0; if(x<=l&&r<=y) { return tr[p].sum; } ll mid=(l+r)>>1; if(x<=mid) ans+=query1(p<<1,l,mid,x,y); if(y>mid) ans+=query1(p<<1|1,mid+1,r,x,y); return ans; } ll query2(ll p,ll l,ll r,ll x,ll y) // 查询 差值最大值 { ll ans=0; if(x<=l&&r<=y) { return tr[p].mx; } ll mid=(l+r)>>1; if(x<=mid) ans=query2(p<<1,l,mid,x,y); if(y>mid) ans=max(ans,query2(p<<1|1,mid+1,r,x,y)); return ans; } ll query3(ll p,ll l,ll r,ll x,ll y) // 查询区间gcd { ll ans=0; if(x<=l&&r<=y) { return tr[p].gcd; } ll mid=(l+r)>>1; if(x<=mid) ans=query3(p<<1,l,mid,x,y); if(y>mid) ans=__gcd(ans,query3(p<<1|1,mid+1,r,x,y)); return ans; } int main() { int n,m; int opt; ll x,y,z; scanf("%d %d",&n,&m); for(int i=1;i<=n;i++) { scanf("%lld",&a[i]); b[i]=a[i]-a[i-1]; } build(1,1,n); ll ans,sum; for(int i=1;i<=m;i++) { scanf("%d",&opt); if(opt==1) { scanf("%lld %lld %lld",&x,&y,&z); update(1,1,n,x,z); if(y+1<=n) update(1,1,n,y+1,-z); } else if(opt==2) { scanf("%lld %lld",&x,&y); if(x==y) { printf("0\n"); continue; } ans=abs(query2(1,1,n,x+1,y)); printf("%lld\n",ans); } else if(opt==3) { scanf("%lld %lld",&x,&y); ll sum=query1(1,1,n,1,x); ll ans=abs(__gcd(sum,query3(1,1,n,x+1,y))); printf("%lld\n",ans); } } return 0; }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。