国际大学生程序设计竞赛例题_3.3儿童节快乐

1,题意:
I a b c给区间[a b]加c个糖果.
C a b选出[a b]最多的糖果,并取出.
2,解决:
动态的区间数据维护,可用线段树解决.
3,实现代码:

#include <iostream>
using namespace std;

#define MAX(a,b) ( a>b? a:b )
const int MAXN=100005;

struct Node
{
int a,b;//左右端点
int m;//区间最多的糖果数
int mIndex;//区间最多糖果数的下标
int r;//区间的糖果数增量
};
Node tree[MAXN*4];

void build(int x,int y,int k)//从位置tree[k]建立线段树
{

tree[k].a=x;
tree[k].b=y;
tree[k].m=0; //初始化为0
tree[k].mIndex=x;
tree[k].r=0;
if(x<y)
{
int mid=(x+y)/2;
build(x,mid,2*k+1);
build(mid+1,y,2*k+2);
}

}

//在节点tree[k]上执行操作I x y p
void insert(int x,int y,int p,int k)
{
if( x<=tree[k].a&&y>=tree[k].b )//x,y完全覆盖了tree[k]的区间
{
tree[k].m+=p; //糖果最多数增加
tree[k].r+=p; //增量
return;
}

int r=tree[k].r;
tree[2*k+1].r+=r;tree[2*k+1].m+=r;
tree[2*k+2].r+=r;tree[2*k+2].m+=r;
tree[k].r=0;//将增量分发给了子区间

int mid=(tree[k].a+tree[k].b)/2;
if(x<=mid)//[x y]与左孩子有交集
insert(x,y,p,2*k+1);
if(y>=mid+1)//与有孩子有交集
insert(x,y,p,2*k+2);

tree[k].m=MAX(tree[2*k+1].m,tree[2*k+2].m);
tree[k].mIndex=tree[2*k+1].m>=tree[2*k+2].m ? tree[2*k+1].mIndex:tree[2*k+2].mIndex;
}

int getmax(int x,int y,int k,int& mindex) //从tree[k]查询[x y]的最大值,将下标保存到mindex
{
if( x<=tree[k].a&&y>=tree[k].b )//x,y完全覆盖了tree[k]的区间
{
mindex=tree[k].mIndex;
return tree[k].m;
}

int r=tree[k].r;
tree[2*k+1].r+=r;tree[2*k+1].m+=r;
tree[2*k+2].r+=r;tree[2*k+2].m+=r;
tree[k].r=0;//将增量分发给了子区间

int mid=(tree[k].a+tree[k].b)/2;
int ret,mindex1,mindex2,r1,r2;
if(x<=mid)//[x y]与左孩子有交集
{
if(y>=mid+1)//与右孩子也有交集
{
r1=getmax(x,y,2*k+1,mindex1);
r2=getmax(x,y,2*k+2,mindex2);
ret=MAX(r1,r2);
mindex=r1>=r2? mindex1:mindex2;
}
else//只与左孩子有交集
{
ret=getmax(x,y,2*k+1,mindex1);
mindex=mindex1;
}
}
else//只与有孩子有交集
{
ret=getmax(x,y,2*k+2,mindex2);
mindex=mindex2;
}
return ret;
}
int main()
{
freopen("3.3.in","r",stdin);
freopen("main.txt","w",stdout);
int n,m;//糖果数,操作数
int ans,mindex;
string op;
int x,y,p;
while(cin>>n>>m,n)
{
build(1,n,0);//初始化线段树
while(m--)
{
cin>>op;
if(op=="I")
{
cin>>x>>y>>p;
insert(x,y,p,0);
}
else
{
cin>>x>>y;
ans=getmax(x,y,0,mindex);
cout<<ans<<endl;
insert(mindex,mindex,-ans,0);//取出糖果数
}
}
}
return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值