codeforce 438D The Child and Sequence

原题链接

简单的线段树单点更新和单点取模

取模的时候暴力会超时,所以优化一下

方法如下:

维护一个线段树最大值数组, 如果 当前节点最大值 都小于 要取模的数 的话,就不向下进行取模操作(因为操作了也没啥用a,还是原来的数)

新手写题可能比较啰嗦qwq

#include<cstdio>
#include<algorithm>
#include<iostream> 
using namespace std;

const int N = 100005;
long long f[N*4], maxx[N*4];

inline void pushup(int root)
{
	maxx[root] = max(maxx[root*2], maxx[root*2+1]);
	f[root] = f[root*2] + f[root * 2 + 1]; 
}
void build(int root, int left, int right)
{
	if(left == right)
	{
		int a;
		cin>>a;
		f[root] = a;
		maxx[root] = a;
		return ;
	}
	
	int mid = (left + right) >> 1;
	int rt = root << 1;
	
	build(rt, left, mid);
	build(rt + 1, mid + 1, right);
	
	f[root] = f[rt] + f[rt + 1];
	maxx[root] = max(maxx[rt], maxx[rt + 1]);
}

void update(int root, int left, int right, int pos, int val)
{
	if(left == right)
	{
		f[root] = maxx[root] = val;
		return ;
	}
	
	int mid = (left + right) >> 1;
	int rt = root << 1;
	
	if(pos <= mid)
	{
		update(rt, left, mid, pos, val);
	}
	else
	{
		update(rt + 1, mid + 1, right, pos, val);
	}
	
	f[root] = f[rt] + f[rt + 1];
	maxx[root] = max(maxx[rt], maxx[rt + 1]);
}

void qmod(int root, int left, int right, int uleft, int uright, int mos)
{
	if(left == right)
	{
		f[root] %=  mos;
		maxx[root] %=  mos;
		return ;
	}
	
	
	int mid = (left + right) >> 1;
	int rt = root << 1;
	
	if(mid >= uleft && mos <= maxx[rt])
	{
		qmod(rt, left, mid, uleft, uright, mos);
	}
	if(mid < uright && mos <= maxx[rt + 1])
	{
		qmod(rt + 1, mid + 1, right, uleft, uright, mos);
	}
	
	f[root] = f[rt] + f[rt + 1];
	maxx[root] = max(maxx[rt], maxx[rt + 1]);
}

long long show(int root, int left, int right, int uleft, int uright)
{
	if(left >= uleft && right <= uright)
	{
		return f[root];
	}
	
	int mid = (left + right) >> 1;
	int rt = root << 1;
	long long ans;
	ans = 0;
	
	if(mid >= uleft)
	{
		ans += show(rt, left, mid, uleft, uright);
	}
	if(mid < uright)
	{
		ans += show(rt+1, mid + 1, right, uleft, uright);
	}
	
	return ans;
}

int main()
{
	int n,m;
	scanf("%d%d", &n, &m);
	build(1,1,n);
	while(m--)
	{
		int j;
		scanf("%d", &j);
		if(j == 1)
		{
			int l, r;
			scanf("%d%d", &l, &r);
			printf("%lld\n", show(1,1,n,l,r));
		}
		else if(j == 2)
		{
			int l,r,x;
			scanf("%d%d%d", &l, &r, &x);
		}
		else if(j == 3)
		{
			int k,x;
			scanf("%d%d", &k, &x);
			update(1,1,n,k,x);
		}
	}
	
	
	
	return 0;
}

ps:最近做线段树真的做的头皮发麻,每次写老是少点啥东西, 比如说这个,我有一个更新最大值的忘写了找了老半天orz

接着去写了886(还是没搞懂区间连续的题呜呜呜俺先从这到入手的HDOJProblem - 1540但是CSDN上的题解都看不懂...看了一天了也好猛,可以有大佬带带我嘛

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值