【悬关】RE 求救
  • 板块学术版
  • 楼主ForMyDream
  • 当前回复0
  • 已保存回复0
  • 发布时间2023/8/25 11:49
  • 上次更新2023/11/3 01:20:28
查看原帖
【悬关】RE 求救
502758
ForMyDream楼主2023/8/25 11:49

rt,用线段树实现的维护区间 gcd,思路是用线段树维护差分

题目

代码

#include<iostream>
#define maxn 500001 
using namespace std;
int n,m;
struct Tree{ // 整个线段树维护的是差分序列 
	int l,r;
	long long sum,d; // 差分区间和、gcd 
	#define lson i<<1
	#define rson i<<1|1
}tree[maxn<<2];
long long a[maxn]; // 原序列 
inline int read();
inline long long Lread();
inline void write(long long x);
//long long gcd(long long a,long long b){ return a%b==0?b:gcd(b,a%b); } 
// ↓这种写法可以应对更大规模的数据 
long long gcd(long long a,long long b){ return b?gcd(b,a%b):a; }
void pushup(Tree &T,Tree L,Tree R){ T.sum=L.sum+R.sum,T.d=gcd(L.d,R.d); }
void build(int i,int l,int r){
	tree[i].l=l,tree[i].r=r;
	if (l==r){ tree[i]={l,r,a[r]-a[r-1],a[r]-a[r-1]}; return; }
	// sum 中存放的是差分和,当 l==r 时就是 d[r],即 a[r]-a[r-1] 
	int mid=l+r>>1;
	build(lson,l,mid),build(rson,mid+1,r);
	pushup(tree[i],tree[lson],tree[rson]);
}
void modify(int i,int p,long long k){
	if (tree[i].l==tree[i].r && tree[i].r==p){ tree[i].sum+=k,tree[i].d+=k; return; }
	int mid=tree[i].l+tree[i].r>>1;
	if (p<=mid) modify(lson,p,k);
	if (p>mid)  modify(rson,p,k);
	pushup(tree[i],tree[lson],tree[rson]);
}
Tree query(int i,int l,int r){
	if (l<=tree[i].l && tree[i].r<=r) return tree[i];
	int mid=tree[i].l+tree[i].r>>1;
	if (r<=mid) return query(lson,l,r); // 查询区间最右边在线段树区间左边,全分布在左子树 
	else if (l>mid) return query(rson,l,r); // 反之,全在左侧。这与之前写过的线段树板子都不一样 
	Tree T; pushup(T,query(lson,l,r),query(rson,l,r));
	// 两个区间都有 
	return T;
}
void output(){ for (int i=1;i<=n*4;i++) printf("%d %d %d %d\n",tree[i].l,tree[i].r,tree[i].sum,tree[i].d); }
int main(){
	n=read(),m=read();
	for (int i=1;i<=n;i++) a[i]=Lread();
	build(1,1,n);
	while (m--){
		// output();
		char ch[2]; scanf("%s",ch); int l=read(),r=read(); 
		if (*ch=='C'){
			long long x=Lread(); modify(1,l,x);
			if (r+1<=n) modify(1,r+1,-x); // 防止越界 
			// 维护的是差分序列,对于原序列的区间修改就是对差分序列的两次单点修改 
		}
		else { // 查询,要分两步查,一部分是左侧的前缀和(构成 a[l]),一部分是右边的 gcd 
			auto left=query(1,1,l),right=query(1,l+1,r);
			write(abs(gcd(left.sum,right.d))); puts(""); 
			// 根据公式,gcd(a[l]~a[r]) = gcd(a[l],a[l+1]-a[l],a[l+2]-a[l+1],...,a[r]-a[r-1])
			//  = gcd(a[l],b[l],b[l+1],b[l+2],...,b[r]) = gcd(a[l],gcd(b[l]~b[r])) 
			// (这里 b 是差分数组 ↑),因为线段树中维护的 sum 是差分序列,所以 
			// = gcd(a[l],query(1,l+1,r).d) = gcd(d[1]+d[2]+...+d[l],query(1,l+1,r).d) 
			// = gcd(query(1,1,l).sum,query(1,l+1).d)
		}
	}
	return 0;
}
inline int read(){
	int ans=0,f=1; char cc=getchar();
	while (cc<'0'||cc>'9'){ if (cc=='-') f=-1; cc=getchar(); }
	while ('0'<=cc && cc<='9'){ ans=(ans<<3)+(ans<<1)+(cc-'0'); cc=getchar(); }
	return f*ans;
} 
inline long long Lread(){
	long long ans=0; int f=1; char cc=getchar();
	while (cc<'0'||cc>'9'){ if (cc=='-') f=-1; cc=getchar(); }
	while ('0'<=cc && cc<='9'){ ans=(ans<<3)+(ans<<1)+(cc-'0'); cc=getchar(); }
	return f*ans;
} 
inline void write(long long x){
	if (x/10>0) write(x/10);
	putchar(x%10+'0');
}

Hack:

in:

5 5
1 3 5 7 9
Q 1 5
C 1 5 1
Q 5 5
C 3 3 6
Q 2 4
1
10
4
2023/8/25 11:49
加载中...