HDU4553 线段树维护最长连续区间

//题意:(略了)
//思路:这里很明显是要维护区间最大连续子段,按照以下优先级查找
//      A1.左边区间的连续子段是否满足
//      A2.左右两个区间中间合并起来的子段是否满足
//      A3.右边区间的连续子段是否满足
//
//      第一次做这种题,遇到的问题在于不知道怎么返回满足条件的子段的起始位置,而实际上我们可以把查找起始位置归类到三种
//      情况上去
//      1.满足条件的子段长度为1,这样起始就是类似于单点查询而已,边界条件是(l==r)
//      2.满足条件的子段长度大于1,这样一来我们总可以将这个子段放到A2的情况上去,从而算出起始点(具体在代码中讲解)
#include<bits/stdc++.h>
using namespace std;
#define lson id<<1,l,mid
#define rson id<<1|1,mid+1,r 
const int N = 1e5 + 50;
struct edge {
	int ls;//左端点开始的连续
	int rs;//右端点开始的连续
	int ms;//区间内的最大连续
	//感觉不适合打标记,因为我的ls和rs需要下层的信息反馈,所以我们干脆一次性向下更新完(其实并不是,这里没标记的原因只是我可以通过值来判断情况而已)
}ds[4 * N], ns[4 * N];
int T, t, n;
void push_down(int id, int l, int r) {
	int mid = (l + r) >> 1;
	if (ds[id].ms == r - l + 1) {//通过上层信息可以推断出下层信息
		ds[id << 1].ms = ds[id << 1].ls = ds[id << 1].rs = mid - l + 1;
		ds[id << 1 | 1].ms = ds[id << 1 | 1].ls = ds[id << 1 | 1].rs = r - mid;
	}
	else if (ds[id].ms == 0) {
		ds[id << 1].ms = ds[id << 1].ls = ds[id << 1].rs = 0;
		ds[id << 1 | 1].ms = ds[id << 1 | 1].ls = ds[id << 1 | 1].rs = 0;
	}

	if (ns[id].ms == r - l + 1) {//通过上层信息可以推断出下层信息
		ns[id << 1].ms = ns[id << 1].ls = ns[id << 1].rs = mid - l + 1;
		ns[id << 1 | 1].ms = ns[id << 1 | 1].ls = ns[id << 1 | 1].rs = r - mid;
	}
	else if (ns[id].ms == 0) {
		ns[id << 1].ms = ns[id << 1].ls = ns[id << 1].rs = 0;
		ns[id << 1 | 1].ms = ns[id << 1 | 1].ls = ns[id << 1 | 1].rs = 0;
	}
}
void update(int id, int l, int r) {
	int mid = (l + r) >> 1;
	ds[id].ls = ds[id << 1].ls;
	ds[id].rs = ds[id << 1 | 1].rs;
	ds[id].ms = max(max(ds[id << 1].ms, ds[id << 1 | 1].ms), ds[id << 1].rs + ds[id << 1 | 1].ls);
	if (ds[id << 1].ms == mid - l + 1) ds[id].ls += ds[id << 1 | 1].ls;
	if (ds[id << 1 | 1].ms == r - mid) ds[id].rs += ds[id << 1].rs;

	ns[id].ls = ns[id << 1].ls;
	ns[id].rs = ns[id << 1 | 1].rs;
	ns[id].ms = max(max(ns[id << 1].ms, ns[id << 1 | 1].ms), ns[id << 1].rs + ns[id << 1 | 1].ls);
	if (ns[id << 1].ms == mid - l + 1) ns[id].ls += ns[id << 1 | 1].ls;
	if (ns[id << 1 | 1].ms == r - mid) ns[id].rs += ns[id << 1].rs;//这几种更新情况要 注意一下
}
void build(int id, int l, int r) {
	ds[id].ls = ns[id].ls = r - l + 1;
	ds[id].rs = ns[id].rs = r - l + 1;
	ds[id].ms = ns[id].ms = r - l + 1;
	if (l == r) return;
	int mid = (l + r) >> 1;
	build(2 * id, l, mid);
	build(2 * id + 1, mid + 1, r);
	update(id, l, r);
}
void change(int id, int l, int r, int ql, int qr, int op) {
	if (l == ql && r == qr) {
		if (op == 1) {
			ds[id].ls = ds[id].rs = ds[id].ms = 0;
		}
		if (op == 2) {
			ds[id].ls = ds[id].rs = ds[id].ms = 0;
			ns[id].ls = ns[id].rs = ns[id].ms = 0;
		}
		if (op == 3) {
			ds[id].ls = ds[id].rs = ds[id].ms = r - l + 1;
			ns[id].ls = ns[id].rs = ns[id].ms = r - l + 1;
		}
		return;
	}
	int mid = (l + r) >> 1;
	push_down(id, l, r);//这里push_down的原因是对这个区间修改后还需要把区间的所有值更新一遍
	if (ql <= mid) change(lson, ql, mid, op);
	if (qr > mid) change(rson, mid + 1, qr, op);
	update(id, l, r);
}
int query(int id, int l, int r, int ans, int op) {
	if (l == r) return 1;
	push_down(id, l, r);
	int mid = (l + r) / 2;
	if (op == 1) {
		if (ds[id << 1].ms >= ans) {		//在左区间 
			return query(lson, ans, op);
		}
		else if (ds[id << 1].rs + ds[id << 1 | 1].ls >= ans) {		//跨越左右,必须先写这个在写查询右边的
			return mid - ds[id << 1].rs + 1;
		}
		else {			//在右区间
			return query(rson, ans, op);
		}
	}
	if (op == 2) {
		if (ns[id << 1].ms >= ans) {		//在左区间 
			return query(lson, ans, op);
		}
		else if (ns[id << 1].rs + ns[id << 1 | 1].ls >= ans) {		//跨越左右,必须先写这个在写查询右边的
			return mid - ns[id << 1].rs + 1;
		}
		else {		//右区间
			return query(rson, ans, op);
		}
	}
}
int main() {
	scanf("%d", &T);
	while (T--) {
		scanf("%d%d", &t, &n);
		build(1, 1, t);
		for (int i = 1; i <= n; i++) {
			string s; int a, b, l, r;
			scanf("%s", &s);
			if (s == "DS") {
				scanf("%d", &a);
				cout << ds[1].ms << endl;
				if (ds[1].ms >= a) {
					l = query(1, 1, t, a, 1);
					r = l + a - 1;
					change(1, 1, t, l, r, 1);
					printf("%d,let's fly\n", l);
				}
				else
					printf("fly with yourself\n");
			}
			else if (s == "NS") {
				scanf("%d", &a);
				if (ds[1].ms >= a) {
					l = query(1, 1, t, a, 1);
					r = l + a - 1;
					printf("%d,don't put my gezi\n", l);
					change(1, 1, t, l, r, 2);
				}
				else if (ns[1].ms >= a) {
					l = query(1, 1, t, a, 2);
					r = l + a - 1;
					printf("%d,don't put my gezi\n", l);
					change(1, 1, t, l, r, 2);
				}
				else
					printf("wait for me\n");
			}
			else {
				scanf("%d%d", &a, &b);
				change(1, 1, t, a, b, 3);
				printf("I am the hope of chinese chengxuyuan!!\n");
			}
		}
	}
	return 0;
}

  

posted @ 2022-12-22 21:13  Aacaod  阅读(23)  评论(0编辑  收藏  举报