HDU-3954:Level up(特殊的线段树成段更新)

来源:互联网 发布:淘宝快递模板下载 编辑:程序博客网 时间:2024/06/06 21:38


题目链接:点击打开链接


题目大意:

有n个英雄,每回合可以执行两种操作,第一种操作你可以给一定区间内的英雄一些经验值。第二种操作就是查询某个区间内的英雄获得的最大经验值。

但是这里英雄有个等级系统,每个英雄初始等级为1,英雄会获得的经验值是 你给予的经验值*自身等级。然后给你升到每级所需要的经验,

但是这里超级坑,例如一共5级,升到每级的经验是 1 2 3 4,那么当英雄获得  2 经验的时候就可以直接升到3级了,我本来一直以为是获得1经验升到2级,再获得2经验升到3级。我艹,为什么这样可以过样例啊,害的我wa了好多发,但是这样也简化了问题,按我理解的题意会稍微复杂一些。反正这个地方要注意,


解题思路:

话说刚看到这道题目,是完全不会做的。心想这怎么打标记啊,完全没办法打延迟标记。结果还是自己水平低啊,大佬都强啊,

其实解决方法也很简单,每个节点需要维护一个当前节点所表示区间内的英雄升级需要的经验的最小值,然后如果他要升级的话就直接访问到子节点让他升级。但是这里要排除等级的影响,因为英雄获得的经验是自身等级*你给的经验。这里也很好解决, 例如一名英雄当前3级,他还差5经验升级。那么他需要的经验就是 5/3 并向上取整,向上取整有个函数或者自己写也是可以的,这样就排除了英雄自身等级的影响,剩下就是维护一个当前区间英雄经验的最大值,和英雄的最大等级,保证这个值得时刻更新,这道题就完美解决了。细节部分可以看代码,


#include<cstdio>#include<cstring>#include<algorithm>#include<iostream>#include<queue>#include<cmath>#define lson rt<<1#define rson rt<<1|1using namespace std;const int N=10010;int n,k,m,ans;char c;int v[20];struct node{    int l,r,mid;    int lazy;       //延迟标记    int level;      //当前区间最大等级    int nv,mv;      //升级所需最小经验和当前区间最大经验}t[N<<2];void pushdown(int rt){    if(t[rt].lazy)      //向下更新    {        t[lson].mv=t[lson].mv+(t[lson].level*t[rt].lazy);        t[rson].mv=t[rson].mv+(t[rson].level*t[rt].lazy);        t[lson].nv=t[lson].nv-t[rt].lazy;        t[rson].nv=t[rson].nv-t[rt].lazy;        t[lson].lazy += t[rt].lazy;        t[rson].lazy += t[rt].lazy;        t[rt].lazy=0;    }}void pushup(int rt)     //子节点向上更新{    t[rt].nv=min(t[lson].nv,t[rson].nv);    t[rt].mv=max(t[lson].mv,t[rson].mv);    t[rt].level=max(t[lson].level,t[rson].level);}void build(int l,int r,int rt)      //建树{                                   //注意在每个节点将所有值初始化    int mid=(l+r)>>1;               //不然会wa,别问我咋知道    t[rt].l=l;t[rt].r=r;    t[rt].mid=mid;    t[rt].lazy=t[rt].mv=0;    t[rt].level=1;    t[rt].nv=ceil((v[t[rt].level+1]-t[rt].mv)/t[rt].level);    if(l==r)        return ;    build(l,mid,lson);    build(mid+1,r,rson);    pushup(rt);}void update(int l,int r,int lev,int rt){    if(l<=t[rt].l&&t[rt].r<=r&&t[rt].nv>lev)    //不能升级,正常更新    {        t[rt].nv=t[rt].nv-lev;        t[rt].mv=t[rt].mv+(lev*t[rt].level);        t[rt].lazy=t[rt].lazy+lev;        return ;    }    if(l<=t[rt].l&&t[rt].r<=r&&t[rt].l==t[rt].r)    //更新到子节点    {        t[rt].mv=t[rt].mv+lev*t[rt].level;        t[rt].lazy=t[rt].lazy+lev;        while(t[rt].mv>=v[t[rt].level+1])       //判断能升到几级,注意一下升多级的情况            t[rt].level++;        t[rt].lazy=0;        t[rt].nv=ceil((v[t[rt].level+1]-t[rt].mv)/t[rt].level); //更新升级最小值        return ;    }    pushdown(rt);    if(l<=t[rt].mid)        update(l,r,lev,lson);    if(r>t[rt].mid)        update(l,r,lev,rson);    pushup(rt);}void query(int l,int r,int rt)      //简单的查询过程{    if(l<=t[rt].l&&t[rt].r<=r)    {        ans=max(ans,t[rt].mv);        return ;    }    pushdown(rt);    if(l<=t[rt].mid)        query(l,r,lson);    if(r>t[rt].mid)        query(l,r,rson);    pushup(rt);}int main(){    int QAQ;    scanf("%d",&QAQ);    int kase=0;while(QAQ--)    {        memset(v,0,sizeof(v));        scanf("%d%d%d",&n,&k,&m);        v[1]=0;        for(int i=2;i<=k;i++)            scanf("%d",&v[i]);        v[k+1]=1<<30;       //这一步当然很重要啊        build(1,n,1);        printf("Case %d:\n",++kase);        while(m--)        {            scanf(" %c",&c);            int p,q,lev;            if(c=='W')            {                scanf("%d%d%d",&p,&q,&lev);                update(p,q,lev,1);            }            if(c=='Q')            {                scanf("%d%d",&p,&q);                ans=0;                query(p,q,1);                printf("%d\n",ans);            }        }        printf("\n");    }}