您的位置:首页 > 其它

「LOJ 6308」「雅礼国庆 2017 Day1」Mod

2018-03-28 21:25 281 查看
LOJ传送门

这道题居然让我想到了 jury_2 的集训队论文,其实确实还是有异曲同工之妙的。

Solution

用线段树维护区间和以及区间最大值

对于操作 1,直接 Query 查询区间和;

对于操作 2,假设当前为区间为 [l,r],若 max{Ai|i∈[l,r]}<x,则直接返回,否则分别递归到左右儿子 [l,mid][mid+1,r],直到 l=r,对 x 取模后返回,更新区间;

对于操作 3,直接 Updata 单点修改。

复杂度为 O((m+n)lognlogw),w 为权值。

Proof

首先是操作 1,3,显然 O(mlogn);

接着是操作 2,分析一下取模的性质:i mod x<i2,这个性质很显然。

于是对于数 ai,我们最多将其修改 O(logai) 次,每次修改为 O(logn)。

由于原数列有 n 个数以及操作 3 至多增加 m 个数,所以总的复杂度为 O((m+n)lognlogw)。

总的来说这还是一道不错的套路题。

#include <cstdio>
#define Max(_A, _B) (_A > _B ? _A : _B)
#define R register
const int MaxN = 100010;
int a[MaxN], B[1 << 18]; long long S[1 << 18];
void Build(R int node, R int begin, R int end)
{
if(begin == end)
{
S[node] = B[node] = a[begin];
return ;
}
R int mid = begin + end >> 1;
Build(node << 1, begin, mid);
Build(node << 1 | 1, mid + 1, end);
S[node] = S[node << 1] + S[node << 1 | 1];
B[node] = Max(B[node << 1], B[node << 1 | 1]);
}
long long Query(R int node, R int begin, R int end, R int l, R int r)
{
if(l <= begin && end <= r) return S[node];
R int mid = begin + end >> 1;
R long long t1 = 0, t2 = 0;
if(l <= mid) t1 = Query(node << 1, begin, mid, l, r);
if(r > mid) t2 = Query(node << 1 | 1, mid + 1, end, l, r);
return t1 + t2;
}
void Updata(R int node, R int begin, R int end, R int pos, R int val)
{
if(begin == end)
{
S[node] = B[node] = val;
return ;
}
R int mid = begin + end >> 1;
if(pos <= mid) Updata(node << 1, begin, mid, pos, val);
else Updata(node << 1 | 1, mid + 1, end, pos, val);
S[node] = S[node << 1] + S[node << 1 | 1];
B[node] = Max(B[node << 1], B[node << 1 | 1]);
}
void Modify(R int node, R int begin, R int end, R int l, R int r, R int val)
{
if(B[node] < val) return ;
if(l <= begin && end <= r)
{
if(begin == end) S[node] = B[node] = S[node] % val;
else
{
R int mid = begin + end >> 1;
if(B[node << 1] >= val) Modify(node << 1, begin, mid, l, r, val);
if(B[node << 1 | 1] >= val) Modify(node << 1 | 1, mid + 1, end, l, r, val);
S[node] = S[node << 1] + S[node << 1 | 1];
B[node] = Max(B[node << 1], B[node << 1 | 1]);
}
return ;
}
R int mid = begin + end >> 1;
if(l <= mid) Modify(node << 1, begin, mid, l, r, val);
if(r > mid) Modify(node << 1 | 1, mid + 1, end, l, r, val);
S[node] = S[node << 1] + S[node << 1 | 1];
B[node] = Max(B[node << 1], B[node << 1 | 1]);
}
int main()
{
R int n, m;
scanf("%d %d", &n, &m);
for(R int i = 1; i <= n; i++) scanf("%d", &a[i]);
Build(1, 1, n);
while(m--)
{
R int opt;
scanf("%d", &opt);
if(opt == 1)
{
R int l, r;
scanf("%d %d", &l, &r);
printf("%lld\n", Query(1, 1, n, l, r));
}
if(opt == 2)
{
R int l, r, x;
scanf("%d %d %d", &l, &r, &x);
Modify(1, 1, n, l, r, x);
}
if(opt == 3)
{
R int k, x;
scanf("%d %d", &k, &x);
Updata(1, 1, n, k, x);
}
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  线段树