题目链接: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;
}