HDU 3308 LCIS(线段树)

HDU 3308 LCIS

题目链接

题意:一个序列,每次询问一个区间内最长连续上升子序列,或者修改一个位置的值

思路:线段树的区间合并,和最长连续子序列和是一样的思路,记录lsum, rsum, sum,表示左边连续长度,右边连续长度,和区间最长长度,然后pushup的时候进行区间合并操作即可

代码:

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;

#define lson(x) ((x<<1)+1)
#define rson(x) ((x<<1)+2)

const int N = 100005;

int t, n, m, a[N];
struct Node {
	int l, r, lsum, rsum, sum;
	int size() {return r - l + 1;}
} node[N * 4];

void merge(Node &x, Node lson, Node rson) {
	x.l = lson.l; x.r = rson.r;
	x.lsum = lson.lsum; x.rsum = rson.rsum; x.sum = max(lson.sum, rson.sum);
	if (a[lson.r] < a[rson.l]) {
		if (lson.lsum == lson.size())
			x.lsum = lson.lsum + rson.lsum;
		if (rson.rsum == rson.size())
			x.rsum = lson.rsum + rson.rsum;
		x.sum = max(x.sum, lson.rsum + rson.lsum);
	}
}

void pushup(int x) {
	merge(node[x], node[lson(x)], node[rson(x)]);
}

void build(int l, int r, int x = 0) {
	node[x].l = l; node[x].r = r;
	if (l == r) {
		node[x].lsum = node[x].rsum = node[x].sum = 1;
		return;
	}
	int mid = (l + r) / 2;
	build(l, mid, lson(x));
	build(mid + 1, r, rson(x));
	pushup(x);
}

void add(int v, int val, int x = 0) {
	if (node[x].l == node[x].r) {
		a[node[x].l] = val;
		return;
	}
	int mid = (node[x].l + node[x].r) / 2;
	if (v <= mid) add(v, val, lson(x));
	if (v > mid) add(v, val, rson(x));
	pushup(x);
}

Node query(int l, int r, int x = 0) {
	if (node[x].l >= l && node[x].r <= r)
		return node[x];
	int mid = (node[x].l + node[x].r) / 2;
	if (l <= mid && r > mid) {
		Node tmp;
		merge(tmp, query(l, r, lson(x)), query(l, r, rson(x)));
		return tmp;
	}
	else if (l <= mid) return query(l, r, lson(x));
	else if (r > mid) return query(l, r, rson(x));
}

int main() {
	scanf("%d", &t);
	while (t--) {
		scanf("%d%d", &n, &m);
		for (int i = 1; i <= n; i++)
			scanf("%d", &a[i]);
		build(1, n);
		char op[2];
		int x, y;
		while (m--) {
			scanf("%s%d%d", op, &x, &y);
			if (op[0] == 'U') add(x + 1, y);
			else printf("%d\n", query(x + 1, y + 1).sum);
		}
	}
	return 0;
}


你可能感兴趣的:(HDU 3308 LCIS(线段树))