CF679 E Bear and Bad Powers of 42(势能分析线段树)

简略题意

给一个序列,支持三种操作:

  1. 查询某个位置的值
  2. 区间赋值
  3. 不断给某个区间加一个数,直到其中不存在42的幂为止。

n 1 0 5 1 0 9 n\leq 10^5,所有输入的数在10^9范围内

思路

  • 看到这种操作基本上就是个势能分析线段树题
  • 构不出太大的数,所以每个数能加的次数就是log次。
  • 将每个位置设为他到下一个幂的距离(真实值为next+dis,即dis通常<0),将正数暴力更新掉。
  • 操作3暴力做,暴力更新距离,是 O ( × log ) O(势能\times\log)
  • 但是操作2会把势能爆炸,怎么办呢
  • 假如当前区间有赋值标记,那么更新正数的时候就一起更新
  • 只要将势能函数定义为“叶子”区间的势能和,就可以证明对某个区间的一段连续的操作对势能的影响也是log级别的。

题解的方法更好理解与证明复杂度,但是写起来会更麻烦。

#include <bits/stdc++.h>
using namespace std;
const int N = 1e5 + 10;
typedef long long ll;
int t[N], n, q;
ll MI[11];
ll tag[N * 4];
typedef pair<ll, int> S;
S mi[N * 4], same[N * 4];
ll near(ll x) {
	return upper_bound(MI + 1, MI + 1 + 10, x) - MI;
}

void build(int x,int l,int r) {
	if (l == r) {
		int u = near(t[l]);
		mi[x] = make_pair(t[l] - MI[u], u);
		return;
	}
	build(x << 1, l, l + r >> 1);
	build(x << 1 | 1, (l + r >> 1) + 1, r);
	mi[x] = max(mi[x << 1], mi[x << 1 | 1]);
}

void putag(int x, ll v) {
	tag[x] += v;
	mi[x].first += v;
}

void put_over(int x, S v) {
	tag[x] = 0;
	same[x] = v;
	mi[x] = v;
}

void down(int x) {
	if (same[x].first) {
		put_over(x << 1, same[x]);
		put_over(x << 1 | 1, same[x]);
		same[x] = make_pair(0, 0);
	}
	if (tag[x]) {
		putag(x << 1, tag[x]);
		putag(x << 1 | 1, tag[x]);
		tag[x] = 0;
	}
}

void add(int x,int l,int r,int tl,int tr,int v) {
	if (tl <= l && r <= tr) {
		putag(x, v);
		return;
	}
	if (l > tr || r < tl) return;
	down(x);
	add(x << 1, l, l + r >> 1, tl, tr, v);
	add(x << 1 | 1, (l + r >> 1) + 1, r, tl, tr ,v);
	mi[x] = max(mi[x << 1], mi[x << 1 | 1]);
}

ll query(int x,int l,int r,int tg) {
	if(l==r)return MI[mi[x].second] + mi[x].first;
	down(x);
	if(tg<=(l+r>>1)) return query(x<<1,l,l+r>>1,tg);
	else return query(x<<1|1,(l+r>>1)+1,r,tg);
}

bool upgrade(int x,int l,int r,int tl,int tr) {
	if (l > tr || r < tl || mi[x].first < 0) return 0;
	if (same[x].first != 0 && tl <= l && r <= tr || l == r) {
		ll v = mi[x].first + MI[mi[x].second];
		int deg = near(v);
		mi[x] = make_pair(v - MI[deg], deg);
		if (same[x].first != 0) {
			same[x] = mi[x];
			tag[x] = 0;
		}
		return mi[x].first + MI[mi[x].second] == MI[mi[x].second - 1];
	}
	down(x);
	bool ret = 0;
	ret |= upgrade(x << 1, l, l + r >> 1, tl, tr);
	ret |= upgrade(x << 1 | 1, (l + r >> 1) + 1, r, tl, tr);
	mi[x] = max(mi[x << 1], mi[x << 1 | 1]);
	return ret;
}

void set_value(int x,int l,int r,int tl,int tr,S v) {
	if (tl <= l && r <= tr) {
		put_over(x, v);
		return;
	}
	if (l > tr || r < tl) return;
	down(x);
	set_value(x << 1, l, l + r >> 1, tl, tr, v);
	set_value(x << 1 | 1, (l + r >> 1) + 1, r, tl, tr ,v);
	mi[x] = max(mi[x << 1], mi[x << 1 | 1]);
}

int main() {
	freopen("e.in","r",stdin);
	cin >> n >> q;
	for(int i = 1; i <= n; i++) {
		scanf("%d", &t[i]);
	}
	MI[0] = 1, MI[1] = 42;
	for(int i = 2; i <= 10; i++) MI[i] = MI[i - 1] * MI[1];
	build(1, 1, n);
	for(int i = 1; i <= q; i++) {
		int ty; scanf("%d", &ty);
		if (ty == 1) {
			int x; scanf("%d", &x);
			printf("%lld\n", query(1, 1, n, x));
		} else {
			int l,r,v; scanf("%d %d %d",&l,&r,&v);
			if (ty == 3) {
				while (1) {
					add(1, 1, n, l, r, v);
					if(!upgrade(1, 1, n, l, r)) break;
				}
			} else {
				int u = near(v);
				set_value(1, 1, n, l, r, make_pair(v - MI[u], u));
			}
		}
	}
}
发布了266 篇原创文章 · 获赞 93 · 访问量 8万+

猜你喜欢

转载自blog.csdn.net/jokerwyt/article/details/102962037