neophyte

从零开始学算法/C++/第二天

已经炉火纯青了,对于[https://sim.csp.thusaac.com/contest/32/problem/3](第32次ccf认证 第四题宝藏) 可不可以用线段树做呢?也许有些困难,哪天闲的没事可以用线段树做一下(每天都很忙:-(
今天做的是[https://www.acwing.com/problem/content/247/](AcWing 246 区间最大公约数)

struct node//这是线段树的结点
{
	int l, r;
	long long gys, sum;
}t[N << 2];

说实话这题很简单,不过还是有收获的->数组a[l]到a[n],设b[i]是a[i]的差分数组,那么a[l]~a[r]这个区间的公约数等于{gcd( a[l], gcd(b[l+1] ~ b[r]) )}
在具体实现中设函数node ffind(int p,int l,int r)返回的是b[l]~b[r]的最大公约数,那么a[l] = ffind( 1, 1, l).
于是

node a = ffind(1, 1, x);
if (x == y)cout << a.sum << endl;
else cout << gcd(a.sum, ffind(1, x + 1, y).gys) << endl;//x,y是要查询的a数组的最大公约数的区间

下面是该题代码

#include<iostream>
#include <algorithm>
#include <cstdlib>
using namespace std;
const int N = 5e5 + 1;
//身不慕生,宁比泰山之重
long long w[N];
int n, m;
long long x, y, d;
char ch;
long long gcd(long long a, long long b) { return b ? gcd(b, a % b) : abs(a); }
struct node
{
	int l, r;
	long long gys, sum;
}t[N << 2];
void build(int p, int l, int r)
{
	t[p] = { l,r };
	if (l == r) { t[p] = { l,l,w[l] - w[l - 1],w[l]-w[l-1]}; return; }
	int mid = l + r >> 1;
	build(p << 1, l, mid);
	build(p << 1 | 1, mid + 1, r);
	t[p].gys = gcd(t[p << 1].gys, t[p << 1 | 1].gys);
	t[p].sum = t[p << 1].sum + t[p << 1 | 1].sum;
}
void jk(int p, int x, long long k)
{
	if (t[p].l == t[p].r) { t[p].sum += k, t[p].gys += k; return; }
	int mid = t[p].l + t[p].r >> 1;
	if (x <= mid)jk(p << 1, x, k);
	else jk(p << 1 | 1, x, k);
	t[p].gys = gcd(t[p << 1].gys, t[p << 1 | 1].gys);
	t[p].sum = t[p << 1].sum + t[p << 1 | 1].sum;
}
node ffind(int p, int l, int r)
{
	if (l <= t[p].l && t[p].r <= r)return t[p];
	int mid = t[p].l + t[p].r >> 1;
	if (r <= mid)return ffind(p << 1, l, r);
	else if (l > mid)return ffind(p << 1 | 1, l, r);
	else
	{
		node a, b, c;
		a = ffind(p << 1, l, r), b = ffind(p << 1 | 1, l, r);
		c.gys = gcd(a.gys, b.gys);
		c.sum = a.sum + b.sum;
		return c;
	}
}
int main()
{
	ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
	cin >> n >> m;
	for (int i = 1; i <= n; ++i)cin >> w[i];
	build(1, 1, n);
	while (m--)
	{
		cin >> ch;
		if (ch == 'C')
		{
			cin >> x >> y >> d;
			if (x > y)swap(x, y);
			jk(1, x, d);
			if (y != n)jk(1, y + 1, -d);
		}
		else
		{
			cin >> x >> y;
			if (x > y)swap(x, y);
			node a = ffind(1, 1, x);
			if (x == y)cout << a.sum << endl;
			else cout << gcd(a.sum, ffind(1, x + 1, y).gys) << endl;
		}
	}
	return 0;
}

写这道题时看到一个很好笑的题解,因为在查询时需要得到数组a的值,题解里面竟然每一次给a数组的区间[l,r]加 d 时都给a数组的[l,r]每一个值都加 d,
那么他写线段树的意义在哪😄
昨天定的任务没有完成,因为今天玩太久了。

posted on 2024-06-15 00:02  俺只是个新手  阅读(10)  评论(0编辑  收藏  举报

导航