比赛描述
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 may contain several test data sets .
For each data set , the first line contains tow integers N , M ( 0 < N , M <= 105 ) where N indicates the number of piles , and M indicates the number of operations that follows .
Each of the next M lines describe 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 .
输出
For each operation C a b , print the number of candies the child can get in a line .
样例输入
5 4
I 1 5 1
C 2 3
I 2 2 4
C 2 3
0 0
样例输出
1
4
题目来源
NUPT ACM
#include <iostream> #include <cstring> #include <cstdio> #define MAXN 100000 using namespace std; struct seg_tree{ int left; //左端点 int right; //右端点 int mid; //中点,向左取整 int num; //这段区间整体需要加的值 int maxn; //这段区间的最大值 int maxi; //这段区间最大值的下标 }seg[MAXN*5]; void build(int left,int right,int i){ //以节点seg[i]为树根建立线段二叉树 seg[i].left = left; seg[i].right = right; seg[i].mid = (left+right)>>1; seg[i].num = seg[i].maxn = 0; seg[i].maxi = left; if (left == right) return; build(left,seg[i].mid,i<<1); build(seg[i].mid+1,right,(i<<1)+1); } void clear_num(int i){ //将本节点的num滑动到两个孩子节点,两个孩子节点要更新num和maxn seg[i<<1].num += seg[i].num; seg[i<<1].maxn += seg[i].num; seg[(i<<1)+1].num += seg[i].num; seg[(i<<1)+1].maxn += seg[i].num; seg[i].num = 0; } void update(int left,int right,int x,int i){ //以节点seg[i]为树根,将区间[left,right]内的数整体加x if(left<=seg[i].left && right>=seg[i].right){ seg[i].num += x; seg[i].maxn += x; return; } if(seg[i].num) clear_num(i); //☆把本节点的num值滑动到下面,否则子节点的max值不正确 if(left <= seg[i].mid) update(left,right,x,i<<1); if(right > seg[i].mid) update(left,right,x,(i<<1)+1); if(seg[i<<1].maxn >= seg[(i<<1)+1].maxn){ //根据两个孩子节点的最大值,更新本节点的额最大值信息 seg[i].maxn = seg[i<<1].maxn; seg[i].maxi = seg[i<<1].maxi; }else{ seg[i].maxn = seg[(i<<1)+1].maxn; seg[i].maxi = seg[(i<<1)+1].maxi; } } void query(int left,int right,int i,int& maxn,int& maxi){ //以节点seg[i]为树根,寻找区间[left,right]内的最大值maxn和最大孩子下标maxi if(left<=seg[i].left && right>=seg[i].right){ if (maxn < seg[i].maxn) { maxn = seg[i].maxn; maxi = seg[i].maxi; } return; } if(seg[i].num) clear_num(i); //将本节点的num值下滑到两个孩子节点,这样在孩子节点得到的最大值才是真正的最大值 if(left <= seg[i].mid) query(left,right,i<<1,maxn,maxi); if(right > seg[i].mid) query(left,right,(i<<1)+1,maxn,maxi); return; } int main(){ int M,N,a,b,c,ansi,ans; char ch; while(scanf("%d%d",&N,&M)!=EOF && (N||M)){ build(1,N,1); while(M--){ getchar(); ch = getchar(); if(ch == 'I'){ scanf("%d%d%d",&a,&b,&c); update(a,b,c,1); }else{ scanf("%d%d",&a,&b); ans = ansi = -1; query(a,b,1,ans,ansi); printf("%d\n",ans); update(ansi,ansi,-ans,1); } } } }