【XSY4041】搬砖(线段树)

题面

搬砖

题解

题意为求最大的 \(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过不去……
posted @ 2022-10-31 07:23  ez_lcw  阅读(18)  评论(0编辑  收藏  举报