HDU 6315

题目连接:naive operations

思路:本题的思路总的来说就是暴力 + 剪枝。

我们依然用线段树来维护:

定义结点node{ l , r , minn , contirbute} 分别为某个区间的左右端点,和该区间(b序列)内的最小值与该区间对答案的贡献。

当我们修改到某一个区间的时候,如果该区间的minn > 1,那么minn--,并且给该区间打上懒标记。

如果该区间的minn == 1,那么我们看一下这个区间的左右两个子区间,对于minn > 1的子区间,我们就采取上面的操作。

对于minn == 1的子区间,我们就一直往下找,直到定位到了最底层的叶子节点,对于该子节点的minn,我们将它复原,但是把它的contribute += 1。

其实就是利用minn值来剪枝。

#include<bits/stdc++.h>
using namespace std;
const int maxn = 1e5 + 5;

struct node {
	int l,r,minn,contri;
};

node store[maxn<<2];
int depot[maxn],add[maxn<<2],n,q;
char op[10];

void pushup(int id) {
	store[id].contri = store[id<<1].contri + store[id<<1 | 1].contri;
	store[id].minn = min(store[id<<1].minn,store[id<<1 | 1].minn);
}
void pushdown(int id) {
	if(add[id]) {
		store[id<<1].minn -= add[id];
		store[id<<1 | 1].minn -= add[id];
		add[id<<1] += add[id];
		add[id<<1 | 1] += add[id];
		add[id] = 0;
	}
}
void build(int l,int r,int id) {
	store[id].l = l,store[id].r = r;
	if(l == r) {
		store[id].minn = depot[l];
		store[id].contri = 0;
		return;
	}
	int mid = (l + r)>>1;
	build(l,mid,id<<1);
	build(mid + 1,r,id<<1 | 1);
	pushup(id);
}
void modify(int l,int r,int id) {

	if(store[id].l == l && store[id].r == r && store[id].minn > 1) {
		store[id].minn -= 1;
		add[id] += 1;
		return;
	}
	if(store[id].l == store[id].r) {
		store[id].minn -= 1;
		add[id] += 1;
		if(store[id].minn <= 0) {
			store[id].minn = depot[l];
			store[id].contri += 1;
		}
		return;
	}
	pushdown(id);
	int mid = (store[id].l + store[id].r)>>1;
	if(r <= mid) modify(l,r,id<<1);
	else if(mid < l) modify(l,r,id<<1 | 1);
	else {
		modify(l,mid,id<<1);
		modify(mid + 1,r,id<<1 | 1);
	}
	pushup(id);
}
int query(int l,int r,int id) {
	if(store[id].l == l && store[id].r == r) {
		return store[id].contri;
	}
	pushdown(id);
	int mid = (store[id].l + store[id].r)>>1;
	int ret = 0;
	if(r <= mid) ret = query(l,r,id<<1);
	else if(mid < l) ret = query(l,r,id<<1 | 1);
	else ret = query(l,mid,id<<1) + query(mid + 1,r,id<<1 | 1);
	pushup(id);
	return ret;
}

int main() {
	while(scanf("%d%d",&n,&q) == 2) {
		memset(add,0,sizeof(add));
		for(int i = 1; i <= n; ++i) {
			scanf("%d",&depot[i]);
		}
		build(1,n,1);
		for(int i = 0; i < q; ++i) {
			int l,r;
			scanf("%s%d%d",op,&l,&r);
			if(op[0] == 'a') {
				modify(l,r,1);
			} 
			else {
				int ans = query(l,r,1);
				printf("%d\n",ans);
			}
		}
	}
	return 0;
}

 

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值