“玲珑杯”ACM比赛 Round #21-C-战舰萝莉(线段树区间更新)

Start Time:2017-09-23 17:00:00 End Time:2017-09-23 19:30:00 Refresh Time:2017-09-23 19:54:51 Private

C -- 战舰萝莉

Time Limit:2s Memory Limit:256MByte

Submissions:66Solved:36

DESCRIPTION

在大战之后,法力浮·鳝AK迅速驾船驶向北海。当然他知道水之灵不可能那么容易得到,正如爱迪生曾说过:“要把BOSS打倒就要准备足够的等级。”所以鳝氪金招募了一队海盗以防战斗。
果不其然,正当鳝看见了水之灵的所在时,一大队舰娘(雾),一大队舰船突然闪现,大战一触即发。
大战前,鳝被对面的boss——北方栖姬吸引了,北方栖姬是一个可爱的小萝莉,实力却很是强劲,而鳝打算把她诱拐回家(雾),打算把她策略击破。
鳝通过提督的观察,发现北方栖姬摆出了“线段树阵形”,具体是这样的:
可以将深海栖舰的舰队看作对一个长度为n的序列建成的线段树,线段树的每个节点维护区间和,记作sumv[o]。这个值同时也是该节点的敌舰所具有的火力。同时在作战过程中,北方栖姬会不断发出区间加和区间减的指令,请注意,这些指令是以打标记的形式维护的,换而言之,某些点的sumv可能不会及时更新。
在每次敌舰队发生变化之后,鳝会问你,当前敌舰队有多少舰是“有威胁”的,我们称一艘舰是有威胁的当且仅当这艘舰的火力>k(一个给定常数)。
作为鳝船上的一名海盗,您需要回答法力浮鳝的所有询问。
下面给出敌舰队的建成,修改的具体示例代码:
http://paste.ubuntu.com/25598285/


题解:直接线段树懒惰标记模拟即可。

#include<set>  
#include<map>     
#include<stack>            
#include<queue>            
#include<vector>    
#include<string> 
#include<time.h>
#include<math.h>            
#include<stdio.h>            
#include<iostream>            
#include<string.h>            
#include<stdlib.h>    
#include<algorithm>   
#include<functional>    
using namespace std;            
#define ll long long       
#define inf  1000000000       
#define mod 1000000007             
#define maxn  136100
#define lowbit(x) (x&-x)            
#define eps 1e-9
int n,k,sum[maxn*5],lazy[maxn*5],ans;
void pushdown(int id,int l,int r)  
{  
    if(lazy[id])  
    {  
		int m=(l+r)/2;
		int tmp=sum[id*2];
        sum[id*2]+=lazy[id]*(m-l+1);
		if(tmp>k && sum[id*2]<=k)
			ans--;
		if(tmp<=k && sum[id*2]>k)
			ans++;
		tmp=sum[id*2+1];
        sum[id*2+1]+=lazy[id]*(r-m);  
		if(tmp>k && sum[id*2+1]<=k)
			ans--;
		if(tmp<=k && sum[id*2+1]>k)
			ans++;
        lazy[id*2]+=lazy[id];  
        lazy[id*2+1]+=lazy[id];  
        lazy[id]=0;  
    }  
}  
void build(int id,int l,int r)
{
	if(l==r)
	{
		scanf("%d",&sum[id]);
		if(sum[id]>k)
			ans++;
		return;
	}
	int mid=(l+r)/2;
	build(id*2,l,mid);
	build(id*2+1,mid+1,r);
	sum[id]=sum[id*2]+sum[id*2+1];
	if(sum[id]>k)
		ans++;
}
void updata(int rt,int L,int R,int l,int r,int add)    
{  
    int m;    
    if(L>=l && R<=r)    
    {   
		int tmp=sum[rt];
        sum[rt]+=add*(R-L+1);  
        lazy[rt]+=add;  
		if(tmp>k && sum[rt]<=k)
			ans--;
		if(tmp<=k && sum[rt]>k)
			ans++;
        return;    
    }  
    pushdown(rt,L,R);  
    m=(L+R)/2;    
    if(l<=m)    
        updata(rt*2,L,m,l,r,add);    
    if(r>m)   
		updata(rt*2+1,m+1,R,l,r,add); 
	int tmp=sum[rt];
    sum[rt]=sum[rt*2]+sum[rt*2+1];   
	if(tmp>k && sum[rt]<=k)
		ans--;
	if(tmp<=k && sum[rt]>k)
		ans++;
}     
int main(void)
{
	int i,t,x,y,z,m;
	scanf("%d%d%d",&n,&m,&k);
	build(1,1,n);
	for(i=1;i<=m;i++)
	{
		scanf("%d%d%d%d",&t,&x,&y,&z);
		if(t==1)
		{
			updata(1,1,n,x,y,z);
			printf("%d\n",ans);
		}
		else
		{
			updata(1,1,n,x,y,-z);
			printf("%d\n",ans);
		}
	}
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值