Codefroces 438D. The Child and Sequence(线段树)

题目链接:http://codeforces.com/contest/438/problem/D

昨晚,吉如一老师做客51Nod给我们讲解了线段树lazy标记的应用,其中,这是最简单的那道题(???)。

这道题目,如果是想完全暴力修改一个区间取模的话,显然是不行的,复杂度太高。这时候,jls教我们用lazy标记去做这道题。

首先,我们有一个结论,有一个数字x,对p取模,如果x < p,那么x显然是不会改变的。如果x >= p,那么,x会改变。

拓展开来,可以得到,如果x对p1取模(x >= p1),然后再对p2取模(p2 > p1),那么这个x肯定是不会再更新了的。(例如3%2=1,然后1%3=1)

所以我们的懒惰标记就用在这个地方了,我们不断维护一个区间的最大模数p,如果判断到输入的模数mod > p,那么就可以直接return不用再更新下面的区间。

这并不是一道lazy标记的典型应用,我们也不需要pushdown这种操作,但他确实减少了修改的常数从而降低复杂度。

靠着jls推荐的模板,我写了一发,调了很久终于过了

- -其他博客上x%p<=x/2(x>=p)到底是什么鬼啊,我根本没用上也不知道怎么用。

代码如下:

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int Maxn = 100000 + 5;
long long a[Maxn];

inline long long unique_input()
{
	bool p = 0;
	char ch = getchar();
	while((ch < '0' || ch > '9') && ch != '-')
		ch = getchar();
	if(ch == '-')
	{
		ch = getchar();
		p = true;
	}
	long long ans = 0;
	while(ch >= '0' && ch <= '9')
	{
		ans = ans * 10 + ch - '0';
		ch = getchar();
	}
	return p ? -ans : ans;
}

struct seg
{
	int l, r;
	long long val, Max;
}segtree[Maxn * 4];

void build(int node, int l, int r)
{
    segtree[node].l = l;
	segtree[node].r = r;
    if(l == r)
    {
    	segtree[node].val = unique_input();
    	segtree[node].Max = segtree[node].val;
		return;
	}
	else
	{
		int mid = (l + r) >> 1;
		int tl = node << 1, tr = node << 1 | 1;
	    build(tl, l, mid);
	    build(tr, mid + 1, r);
	    segtree[node].Max = max(segtree[tl].Max, segtree[tr].Max);
	    segtree[node].val = segtree[tl].val + segtree[tr].val;
	}
}


long long query(int node, int ql, int qr)
{
	if(segtree[node].r < ql || segtree[node].l > qr)//递归进来才判断是否剪枝 
		return 0;
	if(segtree[node].l >= ql && segtree[node].r <= qr)
		return segtree[node].val;
	int mid = segtree[node].l + segtree[node].r >> 1;
	long long res = 0;
	int tl = node << 1, tr = node << 1 | 1;
	res += query(tl, ql, qr);
	res += query(tr, ql, qr);
	return res;
}

void Maintain(int node)
{
	segtree[node].val = segtree[node<<1].val + segtree[node<<1|1].val;
	segtree[node].Max = max(segtree[node<<1].Max, segtree[node<<1|1].Max);
}

bool Cut(int node)
{
	return 0;
}

bool check(int node, int mod)
{
	if(segtree[node].Max < mod)
		return 1;
	return 0;
}

void update_lr(int node, int ql, int qr, long long mod)
{
	if(segtree[node].r < ql || segtree[node].l > qr || Cut(node))//递归进来才判断是否剪枝 
		return;
	if(segtree[node].l >= ql && segtree[node].r <= qr && check(node, mod))
		return;
	if(segtree[node].l == segtree[node].r)
	{
		segtree[node].val %= mod;
		segtree[node].Max = segtree[node].val;
		return;
	} 
	int mid = segtree[node].l + segtree[node].r >> 1;
	update_lr(node << 1, ql, qr, mod);//无脑递归 
	update_lr(node << 1 | 1, ql, qr, mod);
	Maintain(node);
}

void update_point(int node, int x, long long val)
{
	if(segtree[node].r < x || segtree[node].l > x)//递归进来才判断是否剪枝 
		return;
	if(segtree[node].l == x && segtree[node].l == segtree[node].r)
	{
		segtree[node].val = val;
		segtree[node].Max = val;
		return;
	}
	int tl = node << 1, tr = node << 1 | 1;
	update_point(tl, x, val);
	update_point(tr, x, val);
	segtree[node].val = segtree[tl].val + segtree[tr].val;
	segtree[node].Max = max(segtree[tl].Max, segtree[tr].Max);
}

int main()
{
	int n, m, i, ope;
	int l, r;
	long long val;
	scanf("%d%d", &n, &m);
	build(1, 1, n);
	while(m--)
	{
		scanf("%d", &ope);
		if(ope == 1)
		{
			l = unique_input();
			r = unique_input();
			printf("%I64d\n", query(1, l, r));
		}
		else if(ope == 2)
		{
			l = unique_input();
			r = unique_input();
			val = unique_input();
			update_lr(1, l, r, val);
		}
		else
		{
			l = unique_input();
			val = unique_input();
			update_point(1, l, val);
		}	
	}
	return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值