题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3954 , 一道比较好的线段树题,值得做。

  题目是NotOnlySuccess大神出的,借此题来膜拜一下大神,毕竟我学的就是NotOnlySuccess线段树,ORZ。


  这道题比较复杂,如何判断一波经验加成之后是否有英雄需要升级,如果升级需要如何处理,怎样维护Exp的区间最值,都是这道题的难点。

  我在网上百度了别人的题解才敲的出来,具体方法如下:

  线段树上三个数组:level[]表示等级的区间最值;Exp[]表示经验的区间最值; Min标记表示最少需要多少经验基数使该区间有英雄可以升级(刷怪得到的经验 = e * 等级,e就是经验基数)。

  可知每个区间的等级最高的英雄其经验值也是最高的,所以对于每次更新,Exp[rt] += level[rt] * e。对于每次更新,如果当前区间有英雄可以升级,即 e >= Min[rt],那么就把这个区间实行点更新,枚举每个叶子节点检查英雄是否需要升级,英雄升级以后要更新Min标记;如果没有英雄升级,就进行正常的区间更新(更新Min标记,更新Exp值)。

#include <iostream>
#include <cstdio>
#include <vector>
#include <cmath>
#include <string>
#include <string.h>
#include <algorithm>
using namespace std;
#define LL __int64
#define eps 1e-8
#define INF INT_MAX
#define lson l , m , rt << 1
#define rson m + 1 , r , rt << 1 | 1
const int MOD = ;
const int maxn = + ;
const int N = ;
int level[maxn << ] , Exp[maxn << ] , col[maxn << ];
double Min[maxn << ];
int Need[N];
void PushUp(int rt)
{
level[rt] = max(level[rt << ] , level[rt << | ]);
Exp[rt] = max(Exp[rt << ] , Exp[rt << | ]);
Min[rt] = min(Min[rt << ] , Min[rt << | ]);
}
void PushDown(int rt)
{
if(col[rt]) {
col[rt << ] += col[rt];
col[rt << | ] += col[rt];
Min[rt << ] -= col[rt];
Min[rt << | ] -= col[rt];
Exp[rt << ] += level[rt << ] * col[rt];
Exp[rt << | ] += level[rt << | ] * col[rt];
col[rt] = ;
}
}
void build(int l , int r , int rt)
{
if(l == r) {
level[rt] = ;
Exp[rt] = ;
Min[rt] = Need[] * 1.0;
return;
}
col[rt] = ;
int m = (l + r) >> ;
build(lson);
build(rson);
PushUp(rt);
}
void level_up(int e , int l , int r , int rt)
{
if(l == r) { //更新到叶子节点
Exp[rt] += e * level[rt];
while(Exp[rt] >= Need[level[rt] + ])
level[rt]++; //升级英雄
Min[rt] = (Need[level[rt] + ] - Exp[rt]) * 1.0 / level[rt]; //更新Min标记
return;
}
PushDown(rt);
int m = (l + r) >> ;
level_up(e , lson);
level_up(e , rson);
PushUp(rt);
}
void update(int L , int R , int e , int l , int r , int rt)
{
if(l == r) {
Exp[rt] += e * level[rt];
while(Exp[rt] >= Need[level[rt] + ])
level[rt]++;
Min[rt] = (Need[level[rt] + ] - Exp[rt]) * 1.0 / level[rt];
return;
}
if(L <= l && R >= r) {
if(Min[rt] - e > 0.00) { //没有英雄升级
Min[rt] -= e;
col[rt] += e;
Exp[rt] += level[rt] * e;
} else { //有英雄升级
PushDown(rt);
level_up(e , l , r , rt);
PushUp(rt);
}
return;
}
PushDown(rt);
int m = (l + r) >> ;
if(L > m)
update(L , R , e , rson);
else if(R <= m)
update(L , R , e , lson);
else {
update(L , R , e , lson);
update(L , R , e , rson);
}
PushUp(rt);
}
int query(int L , int R , int l , int r , int rt)
{
if(L <= l && R >= r) {
return Exp[rt];
}
PushDown(rt);
int m = (l + r) >> ;
if(L > m)
return query(L , R , rson);
else if(R <= m)
return query(L , R , lson);
else
return max(query(L , R , lson) , query(L , R , rson));
}
int main()
{
int T , K , n , m , i , a , b , c;
char ch[];
cin >> T;
for(int k = ; k <= T ; k++)
{
printf("Case %d:\n" , k);
scanf("%d %d %d" , &n , &K , &m);
for(i = ; i <= K ; i++)
scanf("%d" , &Need[i]);
Need[i] = INF;
build( , n , );
while(m--) {
scanf("%s" , ch);
if(ch[] == 'W') {
scanf("%d %d %d" , &a , &b , &c);
update(a , b , c , , n , );
} else if(ch[] == 'Q') {
scanf("%d %d" , &a , &b);
printf("%d\n" , query(a , b , , n , ));
}
}
puts("");
}
return ;
}

HDU3954 线段树(区间更新 + 点更新)的更多相关文章

  1. HDU 2795 线段树区间最大值,单点更新+二分

    Billboard Time Limit: 20000/8000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total ...

  2. XOR on segment(线段树区间异或更新)

    原题传送门 本题大意:给定n个数字和m个操作,操作共有两种,第一种是求解区间l到r上元素的和,第二种是将区间l到r的元素都异或一个x,作为某个位置的新值. 很容易想到线段树维护区间和,但是我们发现,在 ...

  3. 洛谷 P4513 小白逛公园-区间最大子段和-分治+线段树区间合并(单点更新、区间查询)

    P4513 小白逛公园 题目背景 小新经常陪小白去公园玩,也就是所谓的遛狗啦… 题目描述 在小新家附近有一条“公园路”,路的一边从南到北依次排着nn个公园,小白早就看花了眼,自己也不清楚该去哪些公园玩 ...

  4. hdu 1116 敌兵布阵 线段树 区间求和 单点更新

    线段树的基本知识可以先google一下,不是很难理解 线段树功能:update:单点增减 query:区间求和 #include <bits/stdc++.h> #define lson ...

  5. HDU 1394:Minimum Inversion Number(线段树区间求和单点更新)

    http://acm.hdu.edu.cn/showproblem.php?pid=1394 Minimum Inversion Number Problem Description   The in ...

  6. hdu 3308 线段树 区间合并+单点更新+区间查询

    LCIS Time Limit: 6000/2000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total Submis ...

  7. hdu 1166 线段树 区间求和 +单点更新 CD模板

    题目链接 敌兵布阵 Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total S ...

  8. SPOJ GSS3-Can you answer these queries III-分治+线段树区间合并

    Can you answer these queries III SPOJ - GSS3 这道题和洛谷的小白逛公园一样的题目. 传送门: 洛谷 P4513 小白逛公园-区间最大子段和-分治+线段树区间 ...

  9. HDU 1556 Color the ball(线段树区间更新)

    Color the ball 我真的该认真的复习一下以前没懂的知识了,今天看了一下线段树,以前只会用模板,现在看懂了之后,发现还有这么多巧妙的地方,好厉害啊 所以就应该尽量搞懂 弄明白每个知识点 [题 ...

随机推荐

  1. 将前台传回的HttpServletRequest转换成HashMap

    import java.util.HashMap;import java.util.Map;import java.util.Map.Entry;import java.util.Set; impor ...

  2. .net core关于跨域及Cookie的部分问题

    一.如何跨域 1.情景描述 目前有A站点和B站点.A站点有一个API接口为UserData接口,B站点希望可以通过ajax请求来获取A站点该接口数据. 2.后端修改 首先在ConfigureServi ...

  3. Mybatis学习笔记之一——牛刀小试

    1.Mybaits核心对象SqlSession的作用: (1)向SQL语句传入参数: (2)执行SQl语句: (3)获取执行SQL语句的结果: (4)事务的控制: 2.核心配置文件(Configrat ...

  4. centos 基础设置

    centos 6 关闭防火墙 查看防火墙是否开启 service iptables status 停止防火墙 service iptables stop 禁止开机自启动防火墙 chkconfig ip ...

  5. LeetCode 136 Single Number 数组中除一个数外其他数都出现两次,找出只出现一次的数

    Given an array of integers, every element appears twice except for one. Find that single one. class ...

  6. POJ 3321 Apple Tree DFS序 + 树状数组

    多次修改一棵树节点的值,或者询问当前这个节点的子树所有节点权值总和. 首先预处理出DFS序L[i]和R[i] 把问题转化为区间查询总和问题.单点修改,区间查询,树状数组即可. 注意修改的时候也要按照d ...

  7. Linux Shell命令系列(4)

    16. cat命令 “cat”代表了连结(Concatenation),连接两个或者更多文本文件或者以标准输出形式打印文件的内容. 17. cp 命令 “copy”就是复制.它会从一个地方复制一个文件 ...

  8. 深入理解C#中的IDisposable接口(转)

    转自:https://www.cnblogs.com/wyt007/p/9304564.html 写在前面 在开始之前,我们需要明确什么是C#(或者说.NET)中的资源,打码的时候我们经常说释放资源, ...

  9. Xpath定位绝密版本

    xpath的作用就是两个字“定位”, 运用各种方法进行快速准确的定位,推荐两个非常有用的的firefox工具:firebug和xpath checker 在 XPath 中, 有七种类型的节点:元素. ...

  10. CSS中的IFC和BFC入门

    CSS中的IFC和BFC入门   提到CSS,首先会想到的就是盒模型,如果对于盒模型不是很理解的,看这里.这是一个基础的系列,看了盒模型还可以看看box-sizing,好了不多说了,下面介绍今天的重点 ...