传送门:CCF201709-5 除法
同样是17年10月刚接触编程一个月的蒟蒻的我做过的题,当初是暴力做的,结果必然是超时的QAQ。
这道题想不到会是第五题,直接上树状数组就好了,但还是建了一棵树练了练手,下面会有树状数组和线段树版本的代码。
虽然题目要求的更新是对部分数进行除法,实际上,我们可以对原数组进行预处理,找出满足条件的数,得到商,然后在树上单点修改,就变得非常容易了。但仍有一些需要注意的点,会在代码中注释。下面上代码:
#include <bits/stdc++.h>
#define ll long long
#define INF 0x3f3f3f3f
using namespace std;
const int maxn = 1e5+10;
int n, m;
int a[maxn];
ll ft[maxn];
int lowbit(int x)
{
return x & -x;
}
void update(int x, int val)
{
while(x <= n)
{
ft[x] += val;
x += lowbit(x);
}
}
ll query(int x)
{
ll ret = 0;
while(x > 0)
{
ret += ft[x];
x -= lowbit(x);
}
return ret;
}
void read()
{
cin >> n >> m;
for(int i = 1; i <= n; ++i)
{
cin >> a[i];
update(i, a[i]);
}
}
void solve()
{
int opt, l, r, v;
while(m--)
{
cin >> opt;
if(opt == 1)
{
cin >> l >> r >> v;
if(v == 1) //除以1数不变,故直接continue,节省时间
continue;
for(int i = l; i <= r; ++i)
if(a[i] >= v && a[i]%v == 0) //被除数不能比除数小,否则会变成0,对后续有影响
{
update(i, -(a[i]-a[i]/v)); //除法变为加法
a[i] /= v; //将原数组更新
}
}
else
{
cin >> l >> r;
cout << query(r)-query(l-1) << '\n';
}
}
}
int main()
{
read();
solve();
return 0;
}
线段树:
#include <bits/stdc++.h>
#define ll long long
#define INF 0x3f3f3f3f
using namespace std;
const int maxn = 1e5+24;
int n, t;
ll st[maxn<<2];
int mark[maxn];
void read()
{
scanf("%d%d", &n, &t);
for(int i = 1; i <= n; ++i)
cin >> mark[i];
}
void build(int l, int r, int rt)
{
if(l == r)
{
st[rt] = mark[l];
return;
}
int m = l+((r-l)>>1);
build(l, m, rt<<1);
build(m+1, r, rt<<1|1);
st[rt] = st[rt<<1] + st[rt<<1|1];
}
void update(int L, int l, int r, int rt)
{
if(l == r)
{
st[rt] = mark[L];
return;
}
int m = l+((r-l)>>1);
if(L <= m)
update(L, l, m, rt<<1);
else
update(L, m+1, r, rt<<1|1);
st[rt] = st[rt<<1] + st[rt<<1|1];
}
ll query(int L, int R, int l, int r, int rt)
{
if(L <= l && R >= r)
return st[rt];
int m = l+((r-l)>>1);
ll ret = 0;
if(L <= m)
ret += query(L, R, l, m, rt<<1);
if(R > m)
ret += query(L, R, m+1, r, rt<<1|1);
return ret;
}
int main()
{
read();
build(1, n, 1);
while(t--)
{
int opt, l, r;
cin >> opt;
if(opt == 1)
{
int v;
cin >> l >> r >> v;
if(v == 1)
continue;
for(int i = l; i <= r; ++i)
if(mark[i] >= v && mark[i]%v == 0)
{
mark[i] /= v;
update(i, 1, n, 1);
}
}
else
{
cin >> l >> r;
cout << query(l, r, 1, n, 1) << '\n';
}
}
return 0;
}