CodeForces - 1250C Trip to Saint Petersburg(线段树)

题目链接

题目大意

  给你n个区间,然后你可以选择一个区间[l,r],我们定义S的值为区间[l,r]中包含的所有完整子区间的权值w之和减去\(k\times (r-l+1)\),求最大的S.

解题思路

  这种问题有一种套路就是先固定一个端点,然后枚举另外一个端点,这个题就可以用到。我们将区间按右端点排序,然后每到一个位置i,就将从1到i的区间全部减k,这样从i开始往右数,区间减少的值正好是k,2k,3k...然后因为我们计算的区间要包含完整的子区间,我们的算法是枚举的区间右端点,所以对于一个子区间,它开始有贡献的位置是1-区间左端点的位置,我们枚举到这个区间的时候把1到区间左端点的位置全都加上区间的权值w。然后怎么判断最大的S呢?直接取最大值就行了,最大值对应的位置就是区间S的左端点。

代码

const int maxn = 2e5+10;
const int maxm = 2e5+10;
struct I {
	ll maxx, lz;
} tree[maxn<<2];
int n; ll k;
inline void push_up(int rt) {
	tree[rt].maxx = max(tree[rt<<1].maxx, tree[rt<<1|1].maxx);
}
inline void push_down(int rt) {
	if (tree[rt].lz) {
		ll lz = tree[rt].lz;
		I &ls = tree[rt<<1];
		I &rs = tree[rt<<1|1];
		ls.lz += lz, rs.lz += lz;
		tree[rt<<1].maxx += lz, tree[rt<<1|1].maxx += lz;
		tree[rt].lz = 0;
	}
}
void update(int rt, int l, int r, int a, int b, ll val) {
	if (l>=a && r<=b) {
		tree[rt].lz += val;
		tree[rt].maxx += val;
		return;
	}
	push_down(rt);
	int mid = (l+r)>>1;
	if (a<=mid) update(rt<<1, l, mid, a, b, val);
	if (b>mid) update(rt<<1|1, mid+1, r, a, b, val);
	push_up(rt);
}
ll ask(int rt, int l, int r, int a, int b) {
	if (l>=a && r<=b) return tree[rt].maxx;
	push_down(rt);
	int mid = (l+r)>>1;
	ll maxx = 0;
	if (a<=mid) maxx = max(maxx, ask(rt<<1, l, mid, a, b));
	if (b>mid) maxx = max(maxx, ask(rt<<1|1, mid+1, r, a, b));
	return maxx;
}
int ask2(int rt, int l, int r, ll v) {
	if (l==r) return l;
	push_down(rt);
	int mid = (l+r)>>1;
	if (tree[rt<<1].maxx == v) return ask2(rt<<1, l, mid,  v);
	else return ask2(rt<<1|1, mid+1, r, v);
}
struct I2 {
	int x, i; ll w; 
};
vector<I2> e[maxn];
int main() {	
	cin >> n >> k;
	int x, y; ll w;
	for (int i = 1; i<=n; ++i) {
		scanf("%d%d%lld", &x, &y, &w);
		e[y].push_back({x, i, w});
	}
	ll maxx = 0; P pos;
	for (int i = 1; i<=200000; ++i) {
		update(1, 1, 200000, 1, i, -k);
		for (auto v : e[i]) {
			update(1, 1, 200000, 1, v.x, v.w);
			ll t = ask(1, 1, 200000, 1, v.x);
			if (t>maxx) {
				maxx = t;
				pos = {ask2(1, 1, 200000, maxx), i};
			}
		}
	}
	if (!maxx) {
		cout << 0 << endl;
		return 0;
	}
	vector<int> ans;
	for (int i = pos.x; i<=pos.y; ++i) {
		for (auto v : e[i])
			if (v.x>=pos.x) ans.push_back(v.i);
	}
	cout << maxx << ' ' << pos.x << ' ' << pos.y << ' ' << ans.size() << endl;
	for (auto v : ans) cout << v << ' ';
	return 0;	
} 

posted @ 2021-03-03 09:37  shuitiangong  阅读(43)  评论(0编辑  收藏  举报