HDU6315 Naive Operations

http://acm.hdu.edu.cn/showproblem.php?pid=6315

Problem Description
In a galaxy far, far away, there are two integer sequence a and b of length n.
b is a static permutation of 1 to n. Initially a is filled with zeroes.
There are two kind of operations:

  1. add l r: add one for al,al+1…ar
  2. query l r: query ∑ri=l⌊ai/bi⌋

题意:设计一个数据结构,支持两种操作:
1.[L,R]每个数+1
2.[L,R]每个数除以b[i]向下取整之和

思路:看到这个题想到是线段树,但是查询的这个东西很奇怪,难以维护。
后来读了大佬的这篇blog:https://blog.csdn.net/weixin_39453270/article/details/81211237
因为对于i位置,+b[i]次后,下取整比原来多1,因此如果一个区间+1后没有一个元素达到[除b[i]下取整+1]的地步,我们就可以打一个标记,这样就可以保证线段树的复杂度。
方便实现,我们逆向处理,变加为减,到达b[i]变成到达0。

#include <bits/stdc++.h>
using namespace std;
#define maxn (100000+100)

int n,m,b[maxn];
int ql,qr,_sum;
char cmd[10];
struct SegmentTree{
	int subv[maxn*4],minv[maxn*4],sumv[maxn*4];

	void clear()
	{
		memset(subv,0,sizeof(subv));
		memset(minv,0,sizeof(minv));
		memset(sumv,0,sizeof(sumv));
	}

	void build(int o,int l,int r)
	{
		if(l==r)minv[o]=b[l];
		else
		{
			int mid=(l+r)/2;
			build(o*2,l,mid);
			build(o*2+1,mid+1,r);
			minv[o]=min(minv[o*2],minv[o*2+1]);
		}
	}

	void maintain(int o,int l,int r)
	{
		if(l<r)
		{
			sumv[o]=sumv[o*2]+sumv[o*2+1];
			minv[o]=min(minv[o*2],minv[o*2+1])-subv[o];
		}
		else 
		{
			minv[o]=b[l]-subv[o];
		}
	}

	void pushdown(int o)
	{
		subv[o*2]+=subv[o];
		subv[o*2+1]+=subv[o];
		subv[o]=0;
	}

	void update(int o,int l,int r)
	{
		if(ql<=l&&qr>=r && minv[o]>1)
		{
			subv[o]++;
			maintain(o,l,r);
		}
		else if(l==r)
		{
			minv[o]=b[l];
			sumv[o]++;
			subv[o]=0;
		}
		else
		{
			int mid=(l+r)/2;
			pushdown(o);
			maintain(o*2,l,mid);
			maintain(o*2+1,mid+1,r);
			if(ql<=mid)update(o*2,l,mid);
			if(qr>mid)update(o*2+1,mid+1,r);
			maintain(o,l,r);
		}		
	}

	void query(int o,int l,int r)
	{
		if(ql<=l&&qr>=r)_sum+=sumv[o];
		else
		{
			int mid=(l+r)/2;
			if(ql<=mid)query(o*2,l,mid);
			if(qr>mid)query(o*2+1,mid+1,r);
		}
	}
}tree;

int main()
{
	//freopen("input.in","r",stdin);
	while(cin>>n>>m)
	{
		for(int i=1;i<=n;i++)scanf("%d",&b[i]);
		tree.clear();
		tree.build(1,1,n);
		while(m--)
		{
			scanf("%s%d%d",cmd,&ql,&qr);
			if(cmd[0]=='a')tree.update(1,1,n);
			else
			{
				_sum=0;
				tree.query(1,1,n);
				printf("%d\n",_sum);
			}
		}
	}
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值