维护区间最值做法求调
查看原帖
维护区间最值做法求调
554746
yiming564楼主2024/5/20 21:35

我受 @I_will_AKIOI 的启发,仿效他来维护区间最值来快速筛出操作一需要操作哪些区间。

不同的是,我多维护了一个最大值,这样可以保证严格的时间复杂度。

结果要维护的状态太多了,一下子给自己写炸了。

求大佬帮忙看看,大样例未过但答案接近,误差 ≤0.1%\leq 0.1 \%,悬关。

#include <bits/extc++.h>

const int invaild = -1;
#define inline	__always_inline
using pll = std::pair<int64_t, int64_t>;

inline void read(int &x)
{
	char ch;
	for (ch = getchar(); !isdigit(ch); ch = getchar());
	for (x = 0; isdigit(ch); ch = getchar())	x = x * 10 + ch - '0';
}

class segment_tree_t
{
public:
	struct segment_t
	{
		int l, r;
		inline int size()					const	{ return r - l; }
		inline int mid()					const	{ return l + r >> 1; }
		inline segment_t left()				const	{ return {l, mid()}; }
		inline segment_t right()			const	{ return {mid(), r}; }
		inline bool in(const segment_t &s)	const	{ return s.l <= l && r <= s.r; }
		inline bool out(const segment_t &s)	const	{ return s.r <= l || r <= s.l; }
	};
	struct node_t
	{
		node_t *left, *right;
		segment_t s;
		int64_t set_a, set_b;
		int64_t value_prod, value_sum;
		int64_t add_t;
		pll max_prod, min_prod;
		inline int64_t sum() const
		{
			if (set_a != invaild)
				return (int64_t)(set_a + set_b) * (int64_t)s.size();
			return value_sum + (int64_t)(add_t << 1) * (int64_t)s.size();
		}
		inline int64_t prod() const
		{
			if (set_a != invaild)
				return ((int64_t)set_a * set_b) * (int64_t)s.size();
			return value_prod + value_sum * add_t + (int64_t)add_t * add_t * s.size();
		}
		inline pll max() const 
		{
			if (set_a != invaild)
				return {((int64_t)set_a * set_b), set_a + set_b};
			return {max_prod.first + (max_prod.second + add_t) * add_t, max_prod.second + (int64_t)(add_t << 1)};
		}
		inline pll min() const 
		{ 
			if (set_a != invaild)
				return {((int64_t)set_a * set_b), set_a + set_b};
			return {min_prod.first + (min_prod.second + add_t) * add_t, min_prod.second + (int64_t)(add_t << 1)};
		}
	};
	node_t *root, *stack, *top;
	segment_tree_t(const segment_t &s, int size)
	{
		root = stack = (node_t *)calloc(size, sizeof(node_t));
		*root = {NULL, NULL, s, invaild, invaild};
		top = root + 1;
	}
	~segment_tree_t() { free(stack); }
	inline void push_down(node_t *u)
	{
		if (u->set_a != invaild)
		{
			u->left->set_a = u->right->set_a = u->set_a;
			u->left->set_b = u->right->set_b = u->set_b;
			u->set_a = u->set_b = invaild;
			u->add_t = 0;
		}
		else if (u->add_t)
		{
			if (u->left->set_a == invaild)
				u->left->add_t += u->add_t;
			else
			{
				u->left->set_a += u->add_t;
				u->left->set_b += u->add_t;
			}
			if (u->right->set_a == invaild)
				u->right->add_t += u->add_t;
			else
			{
				u->right->set_a += u->add_t;
				u->right->set_b += u->add_t;
			}
			u->add_t = 0;
		}
	}
	inline void push_up(node_t *u)
	{
		u->value_sum = u->left->sum() + u->right->sum();
		u->value_prod = u->left->prod() + u->right->prod();
		u->max_prod = std::max(u->left->max(), u->right->max());
		u->min_prod = std::min(u->left->min(), u->right->min());
	}
	void build(node_t *u, const segment_t &s, int *a, int *b)
	{
		u->s = s;
		if (s.size() == 1)
		{
			u->set_a = a[s.l];
			u->set_b = b[s.l];
			return;
		}
		u->set_a = u->set_b = invaild;
		build(u->left = top++, s.left(), a, b);
		build(u->right = top++, s.right(), a, b);
		push_up(u);
	}
	void set(node_t *u, const segment_t &s, int a, int b)
	{
		if (u->s.out(s))
			return;
		if (u->s.in(s))
		{
			u->set_a = a;
			u->set_b = b;
			return;
		}
		push_down(u);
		set(u->left, s, a, b);
		set(u->right, s, a, b);
		push_up(u);
	}
	void add(node_t *u, const segment_t &s, int k, int t)
	{
		if (u->s.out(s) || u->min().first > k)
			return;
		if (u->s.in(s) && u->max().first <= k)
		{
			if (u->set_a == invaild)
				u->add_t += t;
			else
			{
				u->set_a += t;
				u->set_b += t;
			}
			return;
		}
		push_down(u);
		add(u->left, s, k, t);
		add(u->right, s, k, t);
		push_up(u);
	}
	int64_t sum(node_t *u, const segment_t &s)
	{
		if (u->s.out(s))
			return 0;
		if (u->s.in(s))
			return u->sum();
		push_down(u);
		push_up(u);
		return sum(u->left, s) + sum(u->right, s);
	}
};


int main()
{
	freopen64("sample1.in", "r", stdin);
	int n, m;
	read(n), read(m);
	int a[n], b[n];
	for (int i = 0; i < n; i++)	read(a[i]);
	for (int i = 0; i < n; i++)	read(b[i]);
	segment_tree_t tree({0, n}, n * 4);
	tree.build(tree.root, {0, n}, a, b);
	int op, x, y; segment_tree_t::segment_t s;
	for (int i = 0; i < m; i++)
	{
		read(op);
		if (op == 1)
		{
			read(s.l), read(s.r), read(x), read(y); s.l--;
			if (y == 0)
				continue;
			tree.add(tree.root, s, x, y);
		}
		else if (op == 2)
		{
			read(s.r), read(x), read(y); s.l = s.r - 1;
			tree.set(tree.root, s, x, y);
		}
		else
		{
			read(s.l), read(s.r); s.l--;
			printf("%ld\n", tree.sum(tree.root, s));
		}
	}
	return 0;
}
2024/5/20 21:35
加载中...