成段更新Problem C(1003)

Problem C (1003)
Happy Children’s Day
Standard Input / Standard Output
Children's Day is coming. In this day, children will get a lot of candies. In MAX city, people develop an automatic candy management (ACM) system. ACM can manage N piles of candies. The system can carry out two operations.
1). I a b c (1<=a<=b<=N, 0<c<=100), ACM will add each pile numbered from a to b with c candies.
2). C a b (1<=a<=b<=N), ACM will choose the pile (from a to b) with the most candies, and give all the candies in that pile to one child. If two or more piles have the most candies, then the pile with smaller id will be chosen.
Given a series of instructions, for each operation C a b, please help the people to find out the number of candies a child can get.
 
Input:
Input may contain several test data sets.
For each data set, the first line contains two integers N, M(0<N,M<=10^5) where N indicates the number of piles, and M indicates the number of operations that follows.
Each of the next M lines describes one operation.
Input will be ended by N=0,M=0,which should not be processed.
 
NOTE: At the beginning of each data set, all of the N piles have 0 candies.
 
Output:
For each operation C a b, print the number of candies the child can get in a line.
 
Sample Input:
5 4
I 1 5 1
C 2 3
I 2 2 4
C 2 3
0 0
 
Sample Output:
1
4
 题目给出了n堆糖,初始都是0个,有两种操作: 1)I a b c 把[a, b]区间的每个堆增加c个糖 2)C a b,表示查询[a, b] 之间 最大值,如果有多个最大值,选取最左边的,并且清空该堆糖。 要求对每一个C操作,输出最大值。 需要更新区间和节点,查询区间,已经开始复杂了,定义三个信息域:除了记录最大值x和其id,作为区间内的最大值靠左的位置,还需要记录cover,表示当前节点相对其以前的值的增加量。利用延迟标记防止更新到点;
我的代码:
#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstring>
#include <algorithm>
#define N 100100
using namespace std;
struct Tree
{
 int l; //左端点
int  r; //右端点
int cover; //延迟标记   表示当前节点相对其以前的值的增加量
int x;
int id;
} tree[N*4]; // 总线段的长度为N,开数组的话一般开到N 的四倍
int data[N];
void push_up(int t)
{
  if(tree[t].cover)
    {
        tree[t*2].x+=tree[t].cover;
        tree[t*2+1].x+=tree[t].cover;
        tree[t*2].cover+=tree[t].cover;
        tree[t*2+1].cover+=tree[t].cover;
        //tree[t*2+1].col=tree[t].val*(tree[t*2+1].r-tree[t*2+1].l+1);
        tree[t].cover=0;
    }
}
void build(int t,int l,int r)
{
    tree[t].l=l;
    tree[t].r=r;
    tree[t].cover=0;
    tree[t].x=0;
    tree[t].id=l;
    if(l==r)
    {
        return;
    }
    int mid=(tree[t].l+tree[t].r)/2;
    if(r<=mid)
    build(t*2,l,r);
    else
    if(l>mid)
    build(t*2+1,l,r);
    else
    {
        build(t*2,l,mid);
        build(t*2+1,mid+1,r);
    }
}
void update(int t,int l,int r,int val)
{
    if(l<=tree[t].l&&r>=tree[t].r)
    {
       tree[t].x+=val;
        tree[t].cover+=val;
        //printf("okoktree[%d]=%d   \n",t,val);
        return;
    }
    push_up(t);
    int mid=(tree[t].l+tree[t].r)/2;
    if(l<=mid)
    update(t*2,l,r,val);
    if(r>mid)
    update(t*2+1,l,r,val);
    tree[t].x=max(tree[t*2].x,tree[t*2+1].x);
    if(tree[t*2].x>=tree[t*2+1].x)
    tree[t].id=tree[t*2].id;
    else
    tree[t].id=tree[t*2+1].id;


}

int query(int t,int l,int r,int &imid)
{
    if(l<=tree[t].l&&r>=tree[t].r)
    {
        //printf("imid=%d\n",tree[t].id);
        imid=tree[t].id;
        return tree[t].x;
    }
    push_up(t);
    int mid=(tree[t].l+tree[t].r)/2;
    int ans=0;
    int id1,id2,a1=0,a2=0;
    if(l<=mid)
    a1=query(t*2,l,r,id1);
    if(r>mid)
    a2=query(t*2+1,l,r,id2);
    if(a1>=a2)//开始搓在这里,没判断;
    {
        ans=a1;imid=id1;
    }
    else
    {
        ans=a2;imid=id2;
    }
    if(a1==0&&a2==0)
    imid=l;
    return ans;
}
int main()
{
    int cas,i,j,k,n,m,t,a,b,z;
    char q[3];
       while(scanf("%d%d",&n,&m)!=EOF)
        {
            if(n==0&&m==0)
            break;
            build(1,1,n);
        for(i=0;i<m;i++)
        {
            cin>>q;
            if(strcmp(q,"I")==0)
            {
                scanf("%d%d%d",&a,&b,&z);
                update(1,a,b,z);
            }
            else
            if(strcmp(q,"C")==0)
            {
                scanf("%d%d",&a,&b);
                int ans=query(1,a,b,z);
                printf("%d\n",ans);
                //printf("id=%d\n",z);
                update(1,z,z,-ans);
            }


        }
        }


    return 0;
}


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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值