hdu 3954

感觉太神了,研究了一天,不过有时候有些题目还是要思考上一段时间才能弄明白题目是怎么做的,貌似对延迟标记又有了更深的理解。

题意:n个英雄, 每个英雄初始经验为0, 初始等级为1, 通过打妖怪可以获得经验从而提高等级, 两种操作

 1 给l, r区间内的英雄加上 k * x的经验

 2 询问l, r区间的最大经验值

分析: 一开始想的太简单了,只是简单的给一段区间做延迟标记, 等到要查询再更新下去,这样的话向下更新的时候登记可能已经变了,所以是不对的, 因为每次经验的获得值为k * x,与等级有关系, 所以要另外开一个域表示该区间可以升级的最小经验基数,一旦加入的经验基数 >= 最小经验基数, 就往下更新, 直到叶子节点或不能更新为止


#include 
   
   
    
    
#include 
    
    
     
     
#include 
     
     
      
      
using namespace std;

struct node {
   int x, y, z;
}a[10010 << 2];
int col[10010 << 2], v[20];
int ql, qr, x;
int n, k, m;
char s[10];

void pushup(int o) {
   a[o].x = max(a[2*o].x, a[2*o+1].x);
   a[o].y = max(a[2*o].y, a[2*o+1].y);
   a[o].z = min(a[2*o].z, a[2*o+1].z);
}
void pushdown(int o) {
   a[2*o].y += a[2*o].x * col[o];
   a[2*o].z -= col[o];
   col[2*o] += col[o];
   a[2*o+1].y += a[2*o+1].x * col[o];
   a[2*o+1].z -= col[o];
   col[2*o+1] += col[o];
   col[o] = 0;
}
void construct(int o, int l, int r) {
   a[o].x = 1;
   a[o].y = 0;
   a[o].z = v[2];
   col[o] = 0;
   if(l == r) return ;
   int m = (l + r) >> 1;
   construct(2*o, l, m);
   construct(2*o+1, m+1, r);
}
void update(int o, int l, int r) {
   if(l == r) {
      a[o].y += a[o].x * x;
      int id = 1;
      for(int i = 2; i <= k; i++)
        if(a[o].y >= v[i]) id = i;
      a[o].x = id;
      if(id == k)  a[o].z = (1 << 31) - 1;
      else {
        a[o].z = (v[id+1] - a[o].y) / id;
        if((v[id+1]-a[o].y) % id) a[o].z++;
      }
      return;
   }
   if(ql <= l && qr >= r) {
      if(x >= a[o].z) {
        if(col[o]) pushdown(o);
        int m = (l + r) >> 1;
        update(2*o, l, m);
        update(2*o+1, m+1, r);
        pushup(o);
      }
      else {
        a[o].y += a[o].x * x;
        a[o].z -= x;
        col[o] += x;
      }
      return ;
   }
   if(col[o])  pushdown(o);
   int m = (l + r) >> 1;
   if(ql <= m)  update(2*o, l, m);
   if(qr > m)   update(2*o+1, m+1, r);
   pushup(o);
}
int query(int o, int l, int r) {
   if(ql <= l && qr >= r) return a[o].y;
   if(col[o])  pushdown(o);
   int m = (l + r) >> 1;
   int ans = 0;
   if(ql<= m)  ans = max(ans, query(2*o, l, m));
   if(qr > m)  ans = max(ans, query(2*o+1, m+1, r));
   return ans;
}
int main() {
  int T, ca = 1;
  scanf("%d", &T);
  while(T--) {
     scanf("%d%d%d", &n, &k, &m);
     for(int i = 2; i <= k; i++) scanf("%d", &v[i]);
     construct(1, 1, n);
     printf("Case %d:\n", ca++);
     while(m--) {
        scanf("%s", s);
        if(s[0] == 'W') {
            scanf("%d%d%d", &ql, &qr, &x);
            update(1, 1, n);
        }
        else {
            scanf("%d%d", &ql, &qr);
            printf("%d\n", query(1, 1, n));
        }
     }
     puts("");
  }
  return 0;
}

     
     
    
    
   
   

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值