【Educational Codeforces Round 37 F】SUM and REPLACE

【链接】 我是链接,点我呀:)
【题意】

在这里输入题意

【题解】

那个D函数它的下降速度是很快的。 也就是说到最后他会很快的变成2或者1 而D(2)==2,D(1)=1 也就是说,几次操作过后很多数字实际上就不会发生变化了。 我们可以以这个为切入点。

可以用树状数组写,也可以用线段树写。

如果用树状数组写的话。
你需要额外用一个set来维护哪些值是还能变化的。
然后在读入l,r这个范围的时候。
直接用lower_bound查找离它最近的且大于等于它的能改变的值。
将它改变。
然后在树状数组中改变对应位置的值。
如果发现改变之后这个数字变成小于等于2了。
那么就在set中删掉这个值。
这样的话.下次在遍历的时候就不会再找到这个值了。
求和的话,还是用树状数组的求和就好了。

如果用线段树的话。
在改变的时候。
直到l==r的时候再改变。
然后维护一个区间的最大值和区间和。
如果区间的最大值<=2那么直接返回这个区间的和就好了。

【代码】

#include <bits/stdc++.h>
#define ll long long
using namespace std;

const int N = 1e6;
const int NN = 3e5;

struct BI {
	ll a[NN + 10];

	int lowbit(int x) {
		return x&(-x);
	}

	void add(int x,int y) {
		while (x <= NN) {
			a[x] += y;
			x += lowbit(x);
		}
	}

	ll sum(int x) {
		ll now = 0;
		while (x > 0) {
			now += a[x];
			x -= lowbit(x);
		}
		return now;
	}

	ll get_sum(int l, int r) {
		return sum(r) - sum(l - 1);
	}

}b;

int f[N+10],n,m,a[NN+10];
set<int> myset;
vector<int> V;

int main(){
	#ifdef LOCAL_DEFINE
	    freopen("rush_in.txt", "r", stdin);
	#endif
	ios::sync_with_stdio(0),cin.tie(0);
    for (int i = 1;i <= N;i++)
            for (int j = i;j <= N;j+=i)
                f[j]++;

    cin >> n >> m;
    for (int i = 1;i <= n;i++) {
        cin >> a[i];
        myset.insert(i);
        b.add(i,a[i]);
    }

    for (int i = 1;i <= m;i++){
        int ope,l,r;
        cin >> ope >> l >> r;
        if (ope==1){

            V.clear();
            while (1){
                auto t = myset.lower_bound(l);
                if (t==myset.end()||(*t)>r) break;
                V.push_back(*t);
                myset.erase(t);
            }

            for (int x:V){
                b.add(x,f[a[x]]-a[x]);
                a[x] = f[a[x]];
                if (a[x]<=2) continue;
                myset.insert(x);
            }
        }else{
            cout<<b.get_sum(l,r)<<endl;
        }
    }

	return 0;
}
原文地址:https://www.cnblogs.com/AWCXV/p/8423719.html