题面
题解
题意为求最大的 \(p\) 使得 \(h_1\equiv h_2\equiv \cdots\equiv h_n\pmod p\)。
即 \(h_2-h_1\equiv h_3-h_2\equiv \cdots\equiv h_n-h_{n-1}\equiv 0\pmod p\)。
那么我们可以得到 \(p|\gcd(h_2-h_1,h_3-h_2,\cdots,h_n-h_{n-1})\)。
令 \(c_i=h_{i+1}-h_i\),那么最大的 \(p\) 就是 \(\gcd(c_1,c_2,\cdots,c_{n-1})\)。
那么我们要做的就是动态维护差分下的全局 \(\gcd\)。
考虑修改操作,对于操作一 \(L,R,a,b,c\) 来说:(其中 \(x\in [L,R)\),注意 \(c_x\) 和 \(c\) 的区分)
\[\begin{aligned} c_x&=h_{x+1}-h_x=\left[a(x+1)^2+b(x+1)+c\right]-\left[ax^2+bx+c\right]\\ &=a(2x+1)+b=2ax+a+b \end{aligned} \]令 \(k=2a\),\(m=a+b\),由 \(\gcd(a,b)=\gcd(a,b-a)\) 可知对于任意的 \(L\leq l<r< R\),有:
\[\begin{aligned} \gcd(c_{l},c_{l+1},\cdots,c_{r})&=\gcd(kl+m,k(l+1)+m,\cdots,k(r-2)+m,k(r-1)+m,kr+m)\\ &=\gcd(kl+m,k(l+1)+m,\cdots,k(r-2)+m,k(r-1)+m,k)\\ &=\gcd(kl+m,k,k,\cdots,k)\\ &=\gcd(kl+m,k)\\ &=\gcd(m,k)\\ \end{aligned} \]那么我们用两棵线段树,一棵 \(T_1\) 维护 \(h_i\),另一棵 \(T_2\) 维护 \(\gcd(c_i)\),然后操作一就相当于在 \(T_1\) 上区间二次函数重置、在 \(T_2\) 上区间重置和单点修改。
而操作二就是来蒙人的……注意到 \(a=b=0\),除了端点外 \(c_i\) 不变,那么我们只需要在 \(T_1\) 上区间加、在 \(T_2\) 上单点修改。
时间复杂度 \(O(n\log n\log w)\),其中 \(n,q\) 同阶,\(w\) 为值域最大值。
#include<bits/stdc++.h>
#define N 200010
#define ll __int128
using namespace std;
inline int read()
{
int x=0,f=1;
char ch=getchar();
while(ch<'0'||ch>'9')
{
if(ch=='-') f=-1;
ch=getchar();
}
while(ch>='0'&&ch<='9')
{
x=(x<<1)+(x<<3)+(ch^'0');
ch=getchar();
}
return x*f;
}
inline void write(ll x,char c)
{
static int a[55];
int cnt=0;
while(x)
{
a[++cnt]=x%10;
x/=10;
}
for(int i=cnt;i>=1;i--)
putchar(a[i]+'0');
putchar(c);
}
ll Abs(ll x)
{
return x<0?-x:x;
}
ll gcd(ll a,ll b)
{
if(!a||!b) return a+b;
return b?gcd(b,a%b):a;
}
struct data
{
int a,b,c;
data(){};
data(int aa,int bb,int cc){a=aa,b=bb,c=cc;}
};
int n,q,h[N];
namespace T1
{
data lazy[N<<2];
bool tag[N<<2];
ll lazadd[N<<2];
void downn(int k,data v)
{
lazy[k]=v;
lazadd[k]=0;
tag[k]=1;
}
void down(int k)
{
if(tag[k])
{
downn(k<<1,lazy[k]);
downn(k<<1|1,lazy[k]);
tag[k]=0;
}
if(lazadd[k])
{
lazadd[k<<1]+=lazadd[k];
lazadd[k<<1|1]+=lazadd[k];
lazadd[k]=0;
}
}
void build(int k,int l,int r)
{
if(l==r)
{
h[l]=lazadd[k]=read();
return;
}
int mid=(l+r)>>1;
build(k<<1,l,mid);
build(k<<1|1,mid+1,r);
}
void update(int k,int l,int r,int ql,int qr,data v)
{
if(ql<=l&&r<=qr)
{
downn(k,v);
return;
}
down(k);
int mid=(l+r)>>1;
if(ql<=mid) update(k<<1,l,mid,ql,qr,v);
if(qr>mid) update(k<<1|1,mid+1,r,ql,qr,v);
}
void change(int k,int l,int r,int ql,int qr,int v)
{
if(ql<=l&&r<=qr)
{
lazadd[k]+=v;
return;
}
down(k);
int mid=(l+r)>>1;
if(ql<=mid) change(k<<1,l,mid,ql,qr,v);
if(qr>mid) change(k<<1|1,mid+1,r,ql,qr,v);
}
ll query(int k,int l,int r,int x)
{
if(l==r)
{
ll ans=0;
if(tag[k]) ans=(ll)lazy[k].a*l*l+(ll)lazy[k].b*l+lazy[k].c;
ans+=lazadd[k];
return ans;
}
down(k);
int mid=(l+r)>>1;
if(x<=mid) return query(k<<1,l,mid,x);
return query(k<<1|1,mid+1,r,x);
}
}
namespace T2
{
int leaf[N<<2];
ll g[N<<2],lazy[N<<2];
bool tag[N<<2];
void up(int k)
{
g[k]=gcd(g[k<<1],g[k<<1|1]);
}
void build(int k,int l,int r)
{
if(l==r)
{
leaf[k]=l;
g[l]=Abs(h[l+1]-h[l]);
return;
}
int mid=(l+r)>>1;
build(k<<1,l,mid);
build(k<<1|1,mid+1,r);
up(k);
}
void downn(int k,ll v)
{
if(!leaf[k])
{
g[k]=lazy[k]=v;
tag[k]=1;
}
}
void getval(int k)
{
g[k]=Abs(T1::query(1,1,n,leaf[k]+1)-T1::query(1,1,n,leaf[k]));
}
void down(int k)
{
if(tag[k])
{
downn(k<<1,lazy[k]);
downn(k<<1|1,lazy[k]);
tag[k]=0;
}
if(leaf[k<<1]) getval(k<<1);
if(leaf[k<<1|1]) getval(k<<1|1);
}
void update(int k,int l,int r,int ql,int qr,ll v)
{
if(ql<=l&&r<=qr)
{
downn(k,v);
return;
}
down(k);
int mid=(l+r)>>1;
if(ql<=mid) update(k<<1,l,mid,ql,qr,v);
if(qr>mid) update(k<<1|1,mid+1,r,ql,qr,v);
up(k);
}
void change(int k,int l,int r,int x)
{
if(l==r) return;
down(k);
int mid=(l+r)>>1;
if(x<=mid) change(k<<1,l,mid,x);
else change(k<<1|1,mid+1,r,x);
up(k);
}
}
int main()
{
n=read(),q=read();
T1::build(1,1,n);
T2::build(1,1,n-1);
while(q--)
{
int opt=read(),l=read(),r=read(),a=read(),b=read(),c=read();
if(opt==1)
{
T1::update(1,1,n,l,r,data(a,b,c));
if(1<=l-1) T2::change(1,1,n-1,l-1);
if(r<=n-1) T2::change(1,1,n-1,r);
if(l==r-1) T2::change(1,1,n-1,r-1);
else if(l<r-1) T2::update(1,1,n-1,l,r-1,gcd(a+b,2*a));
}
if(opt==2)
{
T1::change(1,1,n,l,r,c);
if(1<=l-1) T2::change(1,1,n-1,l-1);
if(r<=n-1) T2::change(1,1,n-1,r);
}
int ans=T2::g[1];
if(!ans) assert(0),ans=T1::query(1,1,n,1);
write(ans,'\n');
}
return 0;
}
/*
5 3
2 2 4 8 12
1 1 3 0 0 4
2 3 5 0 0 8
1 1 5 4 2 4
*/
//不知道为什么95pts过不去……
标签:ch,gcd,线段,XSY4041,kl,cdots,aligned,equiv
From: https://www.cnblogs.com/ez-lcw/p/16842961.html