HDU - 5367 digger(线段树区间合并 + 动态开点)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5367

题目大意:一开始有n座高度为 r 的山峰(编号为1~n),接下来进行q次操作,每次操作可以使得编号在[l ,r]内的山峰的高度改变d,每次操作之后,询问有多少座山峰满足中间一段为连续等高的山峰,同时严格比这些连续的山峰的左边和右边的山峰要高。(编号为1的山峰的左边和编号为n的山峰右边默认为无限高)

题目思路:本题是进行区间修改和区间查询的,所以我们考虑用线段树来维护。根据题目的要求我们可以知道是要维护当前节点所在的区间内连续等高的区间长度,同时维护这个区间左边开始等高的连续区间长度,和右边开始等高的连续区间长度,最左边的山峰的高度,最右边的山峰的高度,以及从最左边开始向右边第一座与最左边的山峰不等高的山峰的高度,同理也要维护从最右边开始向左边第一座与最右边的山峰不等高的山峰的高度。我们可以定义如下的结构体来维护这些信息:

struct Seg_Tree {
	int sum;//区间内满足条件的山峰的数量
	int lsum, rsum;//从最左边开始等高的山峰的区间长度,从最右边开始等高的山峰的区间长度
	int lh, rh;//最左边的山峰的高度,最右边的山峰的高度
	int nlh, nrh;//从最左边开始第一个和最左边的山峰高度不同的山峰的高度,从最右边开始第一个和最右边的山峰高度不同的山峰的高度
};

然后就可以借助线段树的区间合并来维护这些信息了,最后的结果就是根节点的sum。

还有一个问题就是这题的n高达1e9,而且还是一个强制在线的题目。所以我们得用动态开点来维护这些信息。

具体实现看代码:

#include <bits/stdc++.h>
#define fi first
#define se second
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define pb push_back
#define MP make_pair
#define all(v) v.begin(),v.end()
#define clr(a) memset(a,0,sizeof(a))
#define fuck(x) cout<<"["<<#x<<" "<<(x)<<"]\n"
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int>pii;
typedef pair<int, ll>P;
const double pi = acos(-1.0);
const double eps = 1e-8;
const int MX  = 200000 + 7;
const int inf = 0x3f3f3f3f;
//head

int n, q, c;
int tot;
struct Seg_Tree {
	int sum;
	int ls, rs;
	int lsum, rsum;
	int lh, rh;
	int nlh, nrh;
	int lazy;

	void init(int l, int r) {
		lsum = rsum = r - l + 1;
		lazy = sum = lh = rh = ls = rs = nlh = nrh = 0;
	}

	void upd(int val) {
		lazy += val;
		lh += val;
		rh += val;
		nlh += val;
		nrh += val;
	}
} T[MX * 40];

void New_node(int l, int r, int &rt) {
	rt = ++tot;
	T[rt].init(l, r);
	if (l == 1) T[rt].nlh = inf;
	if (r == n) T[rt].nrh = inf;
}
void push_up(int l, int r, int rt) {
	int &ls = T[rt].ls, &rs = T[rt].rs;
	int m = (l + r) >> 1;
	if (!ls) New_node(l, m, ls);
	if (!rs) New_node(m + 1, r, rs);

	T[rt].sum = T[ls].sum + T[rs].sum;

	T[rt].lsum = T[ls].lsum;
	T[rt].rsum = T[rs].rsum;

	T[rt].lh = T[ls].lh;
	T[rt].rh = T[rs].rh;

	T[rt].nlh = T[ls].nlh;
	T[rt].nrh = T[rs].nrh;

	if (T[ls].rh == T[rs].lh) {
		int len = T[ls].rsum + T[rs].lsum;
		if (T[ls].rh > T[ls].nrh && T[ls].rh > T[rs].nlh) T[rt].sum += len;
		if (T[rt].lsum == m - l + 1) {
			T[rt].lsum += T[rs].lsum;
			T[rt].nlh = T[rs].nlh;
		}
		if (T[rt].rsum == r - m) {
			T[rt].rsum += T[ls].rsum;
			T[rt].nrh = T[ls].nrh;
		}
	} else {
		if (T[rt].lsum == m - l + 1) T[rt].nlh = T[rs].lh;
		if (T[ls].rh > T[rs].lh && T[ls].rh > T[ls].nrh) T[rt].sum += T[ls].rsum;

		if (T[rt].rsum == r - m) T[rt].nrh = T[ls].rh;
		if (T[rs].lh > T[ls].rh && T[rs].lh > T[rs].nlh) T[rt].sum += T[rs].lsum;
	}
}
void push_down(int l, int r, int rt) {
	if (T[rt].lazy) {
		int &ls = T[rt].ls, &rs = T[rt].rs;
		int m = (l + r) >> 1;
		if (!ls) New_node(l, m, ls);
		if (!rs) New_node(m + 1, r, rs);

		T[ls].upd(T[rt].lazy);
		T[rs].upd(T[rt].lazy);

		T[rt].lazy = 0;
	}
}
void update(int L, int R, int d, int l, int r, int &rt) {
	if (!rt) New_node(l, r, rt);
	if (L <= l && r <= R) {
		T[rt].upd(d);
		return;
	}
	push_down(l, r, rt);
	int m = (l + r) >> 1;
	if (L <= m) update(L, R, d, l, m, T[rt].ls);
	if (R > m) update(L, R, d, m + 1, r, T[rt].rs);
	push_up(l, r, rt);
}

int main() {
#ifdef ONLINE_JUDGE
#else
	freopen("in.txt", "r", stdin);
#endif
	while (~scanf("%d%d%d", &n, &q, &c)) {
		int root = 0; tot = 0;
		int ans = 0;
		for (int i = 1; i <= q; i++) {
			int l, r, d;
			scanf("%d%d%d", &l, &r, &d);
			l ^= ans; r ^= ans; d ^= ans;
			if (l > r) swap(l, r);
			update(l, r, d, 1, n, root);
			ans = T[root].sum;
			printf("%d\n", ans);
		}
	}
	return 0;
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章