5028: 小Z的加油店(线段树)

  NOI2012魔幻棋盘弱化版

  gcd(a,b,c,d,e)=gcd(a,b-a,c-b,d-c,e-d)

  然后就可以把区间修改变成差分后的点修了。

  用BIT维护原序列,线段树维护区间gcd,支持点修区查

#include<iostream>
#include<cstring>
#include<cstdlib>
#include<cstdio>
#define ll long long
using namespace std;
const int maxn=;
struct poi{int sum;}tree[maxn<<];
int n,m,ty,x,y,z,ans;
int a[maxn],bit[maxn];
void read(int &k)
{
int f=;k=;char c=getchar();
while(c<''||c>'')c=='-'&&(f=-),c=getchar();
while(c<=''&&c>='')k=k*+c-'',c=getchar();
k*=f;
}
inline int gcd(int a,int b){return b?gcd(b,a%b):a;}
inline int lowbit(int x){return x&-x;}
inline void add(int x,int delta){for(;x<=n;x+=lowbit(x))bit[x]+=delta;}
inline int querybit(int x){int sum=;for(;x;x-=lowbit(x))sum+=bit[x];return sum;}
inline void pushup(int x){tree[x].sum=gcd(tree[x<<].sum,tree[x<<|].sum);}
void build(int x,int l,int r)
{
if(l==r){tree[x].sum=a[l]-a[l-];return;}
int mid=(l+r)>>;
build(x<<,l,mid);build(x<<|,mid+,r);
pushup(x);
}
void update(int x,int l,int r,int cx,int delta)
{
if(l==r){tree[x].sum+=delta;return;}
int mid=(l+r)>>;
if(cx<=mid)update(x<<,l,mid,cx,delta);
else update(x<<|,mid+,r,cx,delta);
pushup(x);
}
void query(int x,int l,int r,int cl,int cr)
{
if(cl<=l&&r<=cr){ans=gcd(ans,abs(tree[x].sum));return;}
int mid=(l+r)>>;
if(cl<=mid)query(x<<,l,mid,cl,cr);
if(cr>mid)query(x<<|,mid+,r,cl,cr);
}
int main()
{
read(n);read(m);
for(int i=;i<=n;i++)read(a[i]),add(i,a[i]),add(i+,-a[i]);
build(,,n);
for(int i=;i<=m;i++)
{
read(ty);read(x);read(y);
if(ty==)ans=querybit(x),query(,,n,x+,y),printf("%d\n",ans);
else
{
read(z);add(x,z);add(y+,-z);
update(,,n,x,z);update(,,n,y+,-z);
}
}
}
上一篇:C++ Primer 中文版 5th Edition 练习15.8和练习15.9的解答


下一篇:Linux下chkconfig命令详解 这个简单明了啊