势能线段树

简介

通过定义势能函数 ϕ(i) 去描绘整个序列的势能从而推导正确的复杂度。

例题

P4145 上帝造题的七分钟 2 / 花神游历各国

典。

ϕ(i) 表示第 i 个元素的势能。

一个元素不停的开根一定会变成 1,不妨将元素 x 改写成 2k 的形式。一次开根会将 k 砍半,因此 ϕ(i)=loglogV

放在线段树上,维护区间最大值即可。

时间复杂度 O(nlognloglogV)

代码:

namespace Segment_Tree {
	#define mid (L + R) >> 1
	#define son p, L, R
	#define lson ls(p), L, (L + R) >> 1
	#define rson rs(p), ((L + R) >> 1) + 1, R

	int mx[N << 2], sum[N << 2];

	inline int ls(int p) {
		return p << 1;
	}

	inline int rs(int p) {
		return p << 1 | 1;
	}

	inline void psup(int p) {
		mx[p] = max(mx[ls(p)], mx[rs(p)]);
		sum[p] = sum[ls(p)] + sum[rs(p)];

		return ;
	}

	inline void build(int p = 1, int L = 1, int R = n) {
		if(L == R) {
			mx[p] = sum[p] = a[L];

			return ;
		}

		build(lson), build(rson), psup(p);

		return ;
	}

	inline void add(int l, int r, int p = 1, int L = 1, int R = n) {
		if(mx[p] <= 1) return ;

		if(L == R) {
			sum[p] = sqrt(sum[p]);
			mx[p] = sqrt(mx[p]);

			return ;
		}

		if(l <= mid) add(l, r, lson);
		if(r > mid) add(l, r, rson);

		psup(p);

		return ;
	}

	inline int query(int l, int r, int p = 1, int L = 1, int R = n) {
		if(l <= L && R <= r) return sum[p];

		int res = 0;

		if(l <= mid) res += query(l, r, lson);
		if(r > mid) res += query(l, r, rson);

		return res;
	}

	#undef mid
	#undef son
	#undef lson
	#undef rson
}

P9989 [Ynoi Easy Round 2023] TEST_69

Ynoi!不过是 Easy Round。

还是设 ϕ(i) 表示第 i 个元素的势能。

注意到每次有效操作至少会除去 2 这个最小的因子,由此得出 ϕ(i)=logV

在线段树上维护区间 lcm 判断是否与给出的数 x 有整除关系即可。

时间复杂度 O(nlognlogV)

namespace Segment_Tree {
	#define mid (L + R) >> 1
	#define son p, L, R
	#define lson ls(p), L, (L + R) >> 1
	#define rson rs(p), ((L + R) >> 1) + 1, R

	int sum[N << 2];
	__int128 lcm[N << 2];

	inline __int128 Lcm(__int128 x, __int128 y) {
		return x / __gcd(x, y) * y;
	}

	inline int ls(int p) {
		return p << 1;
	}

	inline int rs(int p) {
		return p << 1 | 1;
	}

	inline void psup(int p) {
		sum[p] = (sum[ls(p)] + sum[rs(p)]) % mod;
		if(Lcm(lcm[ls(p)], lcm[rs(p)]) <= 1e18) lcm[p] = Lcm(lcm[ls(p)], lcm[rs(p)]);
		else lcm[p] = 1e18;

		return ;
	}

	inline void build(int p = 1, int L = 1, int R = n) {
		if(L == R) {
			sum[p] = lcm[p] = a[L];

			return ;
		}

		build(lson), build(rson), psup(p);

		return ;
	}

	inline void add(int l, int r, int k, int p = 1, int L = 1, int R = n) {
		if(Lcm(lcm[p], k) == k) return ;

		if(L == R) {
			sum[p] = __gcd(sum[p], k);
			lcm[p] = sum[p];

			return ;
		}

		if(l <= mid) add(l, r, k, lson);
		if(r > mid) add(l, r, k, rson);

		psup(p);

		return ;
	}

	inline int query(int l, int r, int p = 1, int L = 1, int R = n) {
		if(l <= L && R <= r) return sum[p];

		int res = 0;

		if(l <= mid) res = (res + query(l, r, lson)) % mod;
		if(r > mid) res = (res + query(l, r, rson)) % mod;

		return res % mod;
	}

	#undef mid
	#undef son
	#undef lson
	#undef rson
}
posted @   end_switch  阅读(1)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· 没有源码,如何修改代码逻辑?
· NetPad:一个.NET开源、跨平台的C#编辑器
· PowerShell开发游戏 · 打蜜蜂
· 凌晨三点救火实录:Java内存泄漏的七个神坑,你至少踩过三个!
点击右上角即可分享
微信分享提示