题目链接:点击打开链接
题意:有3种区间操作, 1是把区间内的所有数变成它的欧拉函数值, 2是把区间所有数都变成一个数x,3是查询区间和。
思路:后两个操作就是线段树的区间修改和求和, 没什么好说的。
题解说用平衡树(弱不会), 不过大致思路线段树同样可以维护, 因为一个数进行最多phiO(logn)次就会变成1, 所以我们可以在递归结束,向上传标记的时候顺便看看其子区间是不是都等于1, 是就合并起来, 给这个点重新标记。
细节参见代码:
#include<cstdio> #include<cstring> #include<algorithm> #include<iostream> #include<string> #include<vector> #include<stack> #include<bitset> #include<cstdlib> #include<cmath> #include<set> #include<list> #include<deque> #include<map> #include<queue> using namespace std; typedef long long ll; typedef long double ld; const ld EPS = 1e-9, PI = 3.1415926535897932384626433832795; const int mod = 1000000000 + 7; const int INF = int(1e9); const ll INF64 = ll(1e18); const int maxn = 300000 + 10; int T, n, m, v, id, l, r, x; ll sum[maxn<<2], setv[maxn<<2]; #define Max 10000010 ll euler[Max] = {0}; void Init(){ euler[1]=1; for(ll i=2;i<Max;i++) euler[i]=i; for(ll i=2;i<Max;i++) if(euler[i]==i) for(ll j=i;j<Max;j+=i) euler[j]=euler[j]/i*(i-1); } void PushUp(int o) { sum[o] = sum[o<<1] + sum[o<<1|1]; if(setv[o<<1] == setv[o<<1|1]) setv[o] = setv[o<<1]; else setv[o] = 0; } void build(int l, int r, int o) { int m = (l + r) >> 1; sum[o] = 0; setv[o] = 0; if(l == r) { scanf("%d",&v); sum[o] = setv[o] = v; return ; } build(l, m, o<<1); build(m+1, r, o<<1|1); PushUp(o); } void pushdown(int l, int r, int o) { if(setv[o]) { int m = (l + r) >> 1; setv[o<<1] = setv[o<<1|1] = setv[o]; sum[o<<1] = (ll)(m - l + 1) * setv[o]; sum[o<<1|1] = (ll)(r - m) * setv[o]; setv[o] = 0; } } void update(int L, int R, int v, int l, int r, int o) { int m = (l + r) >> 1; if(L <= l && r <= R) { setv[o] = (ll)v; sum[o] = (ll)v * (r - l + 1); return ; } pushdown(l, r, o); if(L <= m) update(L, R, v, l, m, o<<1); if(m < R) update(L, R, v, m+1, r, o<<1|1); PushUp(o); } void haha(int L, int R, int l, int r, int o) { int m = (l + r) >> 1; if(setv[o] && L <= l && r <= R) { setv[o] = euler[setv[o]]; sum[o] = setv[o] * (r - l + 1); return ; } if(l == r) return ; pushdown(l, r, o); if(L <= m) haha(L, R, l, m, o<<1); if(m < R) haha(L, R, m+1, r, o<<1|1); PushUp(o); } ll query(int L, int R, int l, int r, int o) { int m = (l + r) >> 1; if(L <= l && r <= R) { return sum[o]; } pushdown(l, r, o); ll ans = 0; if(L <= m) ans += query(L, R, l, m, o<<1); if(m < R) ans += query(L, R, m+1, r, o<<1|1); PushUp(o); return ans; } int main() { Init(); scanf("%d",&T); while(T--) { scanf("%d%d",&n,&m); build(1, n, 1); while(m--) { scanf("%d%d%d",&id,&l,&r); if(id == 1) haha(l, r, 1, n, 1); else if(id == 2) { scanf("%d",&x); update(l, r, x, 1, n, 1); } else printf("%I64d\n",query(l, r, 1, n, 1)); } } return 0; }