南邮 OJ 1136 Happy Children’s Day

Happy Children’s Day

时间限制(普通/Java) :  2000 MS/ 6000 MS          运行内存限制 : 65536 KByte
总提交 : 95            测试通过 : 35 

比赛描述

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 ) 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);
			}
        }
    }   
}





你可能感兴趣的:(ACM,happy,day,南邮OJ,Childrens)