首页 > 其他分享 >HDU4553 线段树维护最长连续区间

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

时间:2022-12-22 21:22:21浏览次数:51  
标签:ns int 线段 ds ms id HDU4553 最长 op

//题意:(略了)
//思路:这里很明显是要维护区间最大连续子段,按照以下优先级查找
//      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;
}

  

标签:ns,int,线段,ds,ms,id,HDU4553,最长,op
From: https://www.cnblogs.com/Aacaod/p/16999596.html

相关文章

  • 3. 无重复字符的最长子串
    3.无重复字符的最长子串给定一个字符串s,请你找出其中不含有重复字符的最长子串的长度。输入:s="abcabcbb"输出:3解释:因为无重复字符的最长子串是"abc",所......
  • 【221221-3】一根垂直悬挂的长杆,从地面何处看它最长或视角最大?(使用基本不等式解决)
    ......
  • P3372 【模板】线段树 1
    P3372【模板】线段树1题目简述对于一段数列,有如下两种操作1xyk:将区间\([x,y]\)内每个数加上\(k\)。2xy:输出区间\([x,y]\)内每个数的和。思路线段树......
  • 线段树复习笔记——综合应用(吉司机线段树)
    线段树的综合应用接下来,以洛谷P6242【模板】线段树3(超级毒瘤)为例,来看一下线段树的综合应用。先来看一下此题题意,很熟悉的题面:题目描述给出一个长度为\(n\)的数列......
  • 795前缀和,线段树,树状数组
    题目描述输入一个长度为\(n\)的整数序列。接下来再输入\(m\)个询问,每个询问输入一对\(l,r\)。对于每个询问,输出原序列中从第\(l\)个数到第\(r\)个数的和。输......
  • 每日算法之最长不含重复字符的子字符串
    JZ48最长不含重复字符的子字符串描述请从字符串中找出一个最长的不包含重复字符的子字符串,计算该最长子字符串的长度。示例1输入:"abcabcbb"返回值:3说明:因为无重复......
  • 2022.12.20 线段树复习笔记(未完待续)
    线段树原理及存储:如图,1即为根节点,存储着[1,5]的整个区间和,‘1’为左边界,‘5’为右边界,所以此节点表示的是[1,5]这个区间。线段树的每个节点向下二分,左儿子的编号为此节......
  • leetcode-最长回文子串
    给你一个字符串s,找到s中最长的回文子串。如果字符串的反序与原始字符串相同,则该字符串称为回文字符串。 示例1:输入:s="babad"输出:"bab"解释:"aba"同样是符合题意的答......
  • I Hate It HDU - 1754 - 线段树
    很多学校流行一种比较的习惯。老师们很喜欢询问,从某某到某某当中,分数最高的是多少。这让很多学生很反感。不管你喜不喜欢,现在需要你做的是,就是按照老师的要求,写一个程序,......
  • 最长连续不重复子序列
    题目:给定一个长度为 n 的整数序列,请找出最长的不包含重复的数的连续区间,输出它的长度。输入:第一行包整数n,第二行包含n个整数(均在0∼100000范围内),表示整数序列。输......