HDU 3954 Level up(线段树)

HDU 3954 Level up

题目链接

题意:k个等级,n个英雄,每个等级升级有一定经验,每次两种操作,一个区间加上val,这样区间内英雄都获得当前等级*val的经验,另一个操作询问区间经验最大值

思路:由于等级少,所以每个结点用Max[10]记录下每个等级的最大值,如果有一个升级就一直找到底,因为一个英雄升级最多10次,所以这个操作最多就10W次可以接受,剩下就是普通的区间修改区间查询的延迟操作了

代码:

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

const int N = 10005;
const int M = 11;

int t, n, k, qw, need[M];

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

struct Node {
	int l, r, Max[M], add;
	bool cover;
} node[N * 4];

void build(int l, int r, int x = 0) {
	node[x].l = l; node[x].r = r;
	memset(node[x].Max, -1, sizeof(node[x].Max));
	node[x].Max[1] = 0;
	node[x].add = 0;
	node[x].cover = false;
	if (l == r) return;
	int mid = (l + r) / 2;
	build(l, mid, lson(x));
	build(mid + 1, r, rson(x));
}

bool judge(int x, int v) {
	for (int i = 1; i < k; i++) {
		if (node[x].Max[i] == -1) continue;
		if (node[x].Max[i] + i * v >= need[i + 1]) return true;
	}
	return false;
}

void pushup(int x) {
	node[x].cover = (node[lson(x)].cover && node[rson(x)].cover);
	for (int i = 1; i <= k; i++)
		node[x].Max[i] = max(node[lson(x)].Max[i], node[rson(x)].Max[i]);
}

void pushdown(int x) {
	if (node[x].add) {
		node[lson(x)].add += node[x].add;
		node[rson(x)].add += node[x].add;
		for (int i = 1; i <= k; i++) {
			if (node[lson(x)].Max[i] != -1)
				node[lson(x)].Max[i] += node[x].add * i;
			if (node[rson(x)].Max[i] != -1)
				node[rson(x)].Max[i] += node[x].add * i;
		}
		node[x].add = 0;
	}
}

void add(int l, int r, int v, int x = 0) {
	if (node[x].l >= l && node[x].r <= r && (node[x].cover || !judge(x, v))) {
		node[x].add += v;
		for (int i = 1; i <= k; i++) {
			if (node[x].Max[i] == -1) continue;
			node[x].Max[i] += i * v;
		}
		return;
	}
	if (node[x].l == node[x].r) {
		int have;
		for (int i = 1; i < k; i++) {
			if (node[x].Max[i] != -1) {
				have = node[x].Max[i] + i * v;
				break;
			}
		}
		memset(node[x].Max, -1, sizeof(node[x].Max));
		for (int i = 2; i <= k; i++) {
			if (have < need[i]) {
				node[x].Max[i - 1] = have;
				return;
			}
		}
		node[x].Max[k] = have;
		node[x].cover = true;
		return;
	}
	int mid = (node[x].l + node[x].r) / 2;
	pushdown(x);
	if (l <= mid) add(l, r, v, lson(x));
	if (r > mid) add(l, r, v, rson(x));
	pushup(x);
}

int query(int l, int r, int x = 0) {
	if (node[x].l >= l && node[x].r <= r) {
		for (int i = k; i >= 1; i--) {
			if (node[x].Max[i] == -1) continue;
			return node[x].Max[i];
		}
	}
	int mid = (node[x].l + node[x].r) / 2;
	int ans = 0;
	pushdown(x);
	if (l <= mid) ans = max(ans, query(l, r, lson(x)));
	if (r > mid) ans = max(ans, query(l, r, rson(x)));
	pushup(x);
	return ans;
}

int main() {
	int cas = 0;
	scanf("%d", &t);
	while (t--) {
		printf("Case %d:\n", ++cas);
		scanf("%d%d%d", &n, &k, &qw);
		for (int i = 2; i <= k; i++)
			scanf("%d", &need[i]);
		build(1, n);
		char op[15];
		int a, b, c;
		while (qw--) {
			scanf("%s%d%d", op, &a, &b);
			if (op[0] == 'W') {
				scanf("%d", &c);
				add(a, b, c);
			} else printf("%d\n", query(a, b));
		}
		printf("\n");
	}
	return 0;
}
时间: 2025-01-13 13:39:17

HDU 3954 Level up(线段树)的相关文章

HDU 3954 Level up 线段树

---NotOnlySuccess 出的题--- 看了题之后觉得和HDU 4027有点像,给的K很小,只有10,目测只要有人升级的时候直接更新到叶子节点就ok了.不过不同于HDU 4027 的是,那题每一次更新都相当于这题的一次升级操作,这题里面可能会出现一次操作之后没有升级和出现升级两种情况,一时半会没了思路. 无奈去搜题解,发现我只要维护一个区间当中距离升级最近的人所需要的基础升级经验,即不算等级加成的裸的升级经验,如果在一次涨经验之后,出现当前区间当中有人会升级,直接将每一个要升级的人更新

HDU 4902 Nice boat(线段树)

HDU Nice boat 题目链接 题意:给定一个序列,两种操作,把一段变成x,把一段每个数字,如果他大于x,就变成他和x的gcd,求变换完后,最后的序列. 思路:线段树,每个结点多一个cover表示该位置以下区间是否数字全相同,然后每次延迟操作,最后输出的时候单点查询即可 代码: #include <cstdio> #include <cstring> #include <algorithm> using namespace std; const int N = 1

hdu 2795 Billboard(线段树)

Billboard Time Limit: 20000/8000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 10890    Accepted Submission(s): 4827 Problem Description At the entrance to the university, there is a huge rectangular billboard of

hdu 3016 Man Down (线段树 + dp)

题目大意: 是男人就下一般层...没什么可以多说的吧. 注意只能垂直下落. 思路分析: 后面求最大值的过程很容易想到是一个dp的过程 . 因为每一个plane 都只能从左边 从右边下两种状态. 然后我们所需要处理的问题就是 ,你如何能快速知道往左边下到哪里,往右边下到哪里. 这就是线段树的预处理. 讲线段按照高度排序. 然后按照高度从小到大加入到树中. 然后去寻找左端点 和 右端点最近覆盖的线段的编号. #include <cstdio> #include <iostream> #

多校训练hdu --Nice boat(线段树,都是泪)

Nice boat Time Limit: 30000/15000 MS (Java/Others) Memory Limit: 131072/131072 K (Java/Others) Total Submission(s): 47 Accepted Submission(s): 10 Problem Description There is an old country and the king fell in love with a devil. The devil always ask

HDU 3308 LCIS(线段树)

Problem Description Given n integers.You have two operations:U A B: replace the Ath number by B. (index counting from 0)Q A B: output the length of the longest consecutive increasing subsequence (LCIS) in [a, b]. Input T in the first line, indicating

HDU 2795 Billboard (线段树单点更新)

题意:h,w,n:有一个h*w尺寸的木板,n张1*wi的海报,贴海报的位置尽量高,尽量往左,问每张海报贴的高度 看到1 <= h,w <= 10^9; 1 <= n <= 200,000,应该就是线段树了. 关键在怎么建树,这里我们对h进行分割,每个高度都有等长的w,我们从上往下贴,如果当前高度 (在同一高度上l==r)的长度可以满足wi则可以贴,否则继续往下寻找. #include <iostream> #include <stdio.h> #includ

HDU—4046 Panda (线段树)

题目:http://acm.hdu.edu.cn/showproblem.php?pid=4046 题意:给出一个字符串,统计这个字符串任意区间中"wbw"出现的次数. 规定两种操作,一是查询任意区间"wbw"出现次数:二是修改某一位置的字符. 分析:比较明显的线段树,单点更新,区间查询. 线段树记录的信息是区间中出现"wbw"字符的个数,线段树的叶子节点[i,i]记录字符串str中 str[i-2][i-1][i]是否是"wbw&qu

hdu 5700区间交(线段树)

区间交 Time Limit: 8000/4000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)Total Submission(s): 849    Accepted Submission(s): 377 Problem Description 小A有一个含有n个非负整数的数列与m个区间.每个区间可以表示为li,ri. 它想选择其中k个区间, 使得这些区间的交的那些位置所对应的数的和最大. 例如样例中,选择[2,5]