动态开点线段树玄学问题求解
查看原帖
动态开点线段树玄学问题求解
790188
bsdsdb楼主2024/6/21 12:48
#include <bits/stdc++.h>
typedef long long ll;
using namespace std;

const ll MAXN = 1e5, MAXV = 1e5;

struct sec {
	ll id, val, l, r, len;
	sec(ll i, ll v, ll lf, ll rg, ll ln) {
		id = i;
		val = v;
		l = lf;
		r = rg;
		len = ln;
	}
	sec() {
		id = val = l = r = len = 0;
	}
};
struct opr {
	ll val;
	opr(ll v) {
		val = v;
	}
	opr() {
		val = 0;
	}
};
sec com(sec x, sec y, ll i) {
	return sec(i, x.val + y.val, x.id, y.id, x.len + y.len);
}
sec com(sec x, opr y) {
	return sec(x.id, x.val + y.val * x.len, x.l, x.r, x.len);
}
opr com(opr x, opr y) {
	return opr(x.val + y.val);
}
sec com(sec x, ll y) {
	return com(x, opr(y));
}
opr com(opr x, ll y) {
	return com(x, opr(y));
}
struct segTree {
	ll size, rt;
	vector<sec> val;
	vector<opr> tag;
	void pushdown(ll x) {
		tag[val[x].l] = com(tag[val[x].l], tag[x]);
		val[val[x].l] = com(val[val[x].l], tag[x]);
		tag[val[x].r] = com(tag[val[x].r], tag[x]);
		val[val[x].r] = com(val[val[x].r], tag[x]);
		tag[x] = tag[0] = opr();
		val[0] = sec();
	}
	void pushup(ll x) {
		val[x] = com(val[val[x].l], val[val[x].r], x);
	}
	segTree() {
		val.push_back(sec());
		val.push_back(sec(1, 0, 0, 0, MAXV));
		tag.push_back(opr());
		tag.push_back(opr());
		size = MAXV;
		rt = 1;
	}
	ll mdf(ll x, ll lx, ll rx, ll l, ll r, ll k) {
		if (x == 0) {
			x = val.size();
			val.push_back(sec(x, 0, 0, 0, rx - lx));
			tag.push_back(opr());
		}
		if (r <= lx || rx <= l) {
			return x;
		}
		if (l <= lx && rx <= r) {
			tag[x] = com(tag[x], k);
			val[x] = com(val[x], k);
			return x;
		}
		pushdown(x);
		ll mid = (lx + rx) / 2;
		ll lc = mdf(val[x].l, lx, mid, l, r, k);
		val[x].l = lc;
		ll rc = mdf(val[x].r, mid, rx, l, r, k);
		val[x].r = rc;
		pushup(x);
		return x;
	}
	ll qry(ll x, ll lx, ll rx, ll l, ll r) {
		if (x == 0) {
			return sec().val;
		}
		if (r <= lx || rx <= l) {
			return sec().val;
		}
		if (l <= lx && rx <= r) {
			return val[x].val;
		}
		pushdown(x);
		ll mid = (lx + rx) / 2;
		return qry(val[x].l, lx, mid, l, r) + qry(val[x].r, mid, rx, l, r);
	}
	void out(ll x, ll lx, ll rx) {
		if (x == 0) {
			return;
		}
		cout << "val[" << x << "[" << lx << "," << rx - 1 << "]]=" << val[x].val << " " << val[x].l << " " << val[x].r << " " << val[x].len << endl;
		cout << "tag[" << x << "[" << lx << "," << rx - 1 << "]]=" << tag[x].val << endl;
		ll mid = (lx + rx) / 2;
		out(val[x].l, lx, mid);
		out(val[x].r, mid, rx);
	}
} st;

ll n, q;

int main() {
	cin >> n >> q;
	for (ll i = 1; i <= n; i++) {
		ll v;
		cin >> v;
		st.mdf(st.rt, 1, st.size + 1, i, i + 1, v);
	}
	while (q--) {
		ll o, l, r, k;
		cin >> o >> l >> r;
		if (o == 1) {
			cin >> k;
			st.mdf(st.rt, 1, st.size + 1, l, r + 1, k);
		} else {
			cout << st.qry(st.rt, 1, st.size + 1, l, r + 1) << endl;
		}
	}
	return 0;
}

可以AC,但是如果将代码中的

ll lc = mdf(val[x].l, lx, mid, l, r, k);
val[x].l = lc;
ll rc = mdf(val[x].r, mid, rx, l, r, k);
val[x].r = rc;

换成

val[x].l = mdf(val[x].l, lx, mid, l, r, k);
val[x].r = mdf(val[x].r, mid, rx, l, r, k);

就会7WA3RE(但是mac上下载数据测试能AC,洛谷就不行),调试发现有时候子树编号会被赋值为0,即使mdf返回的值是正确的

如果把mdf中的x换成引用:

ll mdf(ll& x, ll lx, ll rx, ll l, ll r, ll k) {
	if (x == 0) {
		x = val.size();
		val.push_back(sec(x, 0, 0, 0, rx - lx));
		tag.push_back(opr());
	}
	if (r <= lx || rx <= l) {
		return x;
	}
	if (l <= lx && rx <= r) {
		tag[x] = com(tag[x], k);
		val[x] = com(val[x], k);
		return x;
	}
	pushdown(x);
	ll mid = (lx + rx) / 2;
	mdf(val[x].l, lx, mid, l, r, k);
	mdf(val[x].r, mid, rx, l, r, k);
	pushup(x);
	return x;
}

就是1WA3RE,调试后发现在val push_back之后上层递归中的x会莫名其妙地变成0

why?

2024/6/21 12:48
加载中...