HDU 5634 线段树
Posted キリト
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了HDU 5634 线段树相关的知识,希望对你有一定的参考价值。
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5634
题意:给定一个长度为n的序列,有m次操作。操作有3种:
1 l,r :区间[l,r]的值变成phi[val[i]](l<=i<=r; phi是欧拉值)
2 l,r,x:区间[l,r]的值变成x
3 l,r:求区间[l,r]的和
思路:操作2和3就是传统的简单线段树,操作2对应区间覆盖,操作3对应区间求和,重点在于操作1,由于一个数经过不超过log次求phi后会变成1,所以可以在线段树是用一个same标记,如果整个区间的数都相同则操作1就转换成操作2的区间覆盖了。如果操作的区间[l,r]已经包含住当前递归的子树区间但是子树的same标记为假则继续递归到子树的same标记为真为止,最多递归到叶子结点。
#define _CRT_SECURE_NO_DEPRECATE #include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<string> #include<queue> #include<vector> #include<time.h> #include<cmath> using namespace std; typedef long long int LL; #define L(k)(k<<1) #define R(k)(k<<1|1) const LL INF = 9223372036854775807; const int MAXN = 3e5 + 24; const int MAXX = 1e7 + 24; struct Node{ int l, r, val; LL sum; bool same; Node(int _l = 0, int _r = 0, int _val = 0, LL _sum = 0, bool _same = false){ l = _l; r = _r; sum = _sum; same = _same; val = _val; } }Seg[MAXN * 4]; int val[MAXN], Phi[MAXX]; void pushUp(int k){ Seg[k].sum = Seg[L(k)].sum + Seg[R(k)].sum; if (Seg[L(k)].val == Seg[R(k)].val&&Seg[L(k)].same&&Seg[R(k)].same&&Seg[L(k)].val != -1){ Seg[k].same = true; Seg[k].val = Seg[L(k)].val; } else{ Seg[k].same = false; Seg[k].val = -1; } } void pushDown(int k){ if (Seg[k].same){ Seg[L(k)].same = Seg[R(k)].same = true; Seg[L(k)].val = Seg[R(k)].val = Seg[k].val; Seg[L(k)].sum = 1LL * (Seg[L(k)].r - Seg[L(k)].l + 1)*Seg[L(k)].val; Seg[R(k)].sum = 1LL * (Seg[R(k)].r - Seg[R(k)].l + 1)*Seg[R(k)].val; } } void Build(int st, int ed, int k){ Seg[k].l = st; Seg[k].r = ed; Seg[k].same = false; Seg[k].val = -1; if (st == ed){ Seg[k].val = val[st]; Seg[k].sum = val[st]; Seg[k].same = true; return; } int mid = (st + ed) >> 1; Build(st, mid, L(k)); Build(mid + 1, ed, R(k)); pushUp(k); } void Change(int st, int ed, int val, int k){ if (Seg[k].l == st&&Seg[k].r == ed){ Seg[k].same = true; Seg[k].val = val; Seg[k].sum = 1LL * (ed - st + 1)*val; return; } pushDown(k); if (Seg[L(k)].r >= ed){ Change(st, ed, val, L(k)); } else if (Seg[R(k)].l <= st){ Change(st, ed, val, R(k)); } else{ Change(st, Seg[L(k)].r, val, L(k)); Change(Seg[R(k)].l, ed, val, R(k)); } pushUp(k); } void Modify(int st, int ed, int k){ if (Seg[k].l == st&&Seg[k].r == ed&&Seg[k].same){ Seg[k].val = Phi[Seg[k].val]; Seg[k].sum = 1LL * (ed - st + 1)*Seg[k].val; return; } pushDown(k); if (Seg[L(k)].r >= ed){ Modify(st, ed, L(k)); } else if (Seg[R(k)].l <= st){ Modify(st, ed, R(k)); } else{ Modify(st, Seg[L(k)].r, L(k)); Modify(Seg[R(k)].l, ed, R(k)); } pushUp(k); } LL Query(int st, int ed, int k){ if (Seg[k].l == st&&Seg[k].r == ed){ return Seg[k].sum; } pushDown(k); if (Seg[L(k)].r >= ed){ return Query(st, ed, L(k)); } else if (Seg[R(k)].l <= st){ return Query(st, ed, R(k)); } else{ return Query(st, Seg[L(k)].r, L(k)) + Query(Seg[R(k)].l, ed, R(k)); } pushUp(k); } void GetPhi(){ //预处理欧拉值 memset(Phi, 0, sizeof(Phi)); Phi[1] = 1; for (LL i = 2; i < MAXX; i++){ if (!Phi[i]){ for (LL j = i; j < MAXX; j += i){ if (!Phi[j]) Phi[j] = j; Phi[j] = Phi[j] / i*(i - 1); } } } } int main(){ //#ifdef kirito // freopen("in.txt", "r", stdin); // freopen("out.txt", "w", stdout); //#endif // int start = clock(); int n, t, m; GetPhi(); scanf("%d", &t); while (t--){ scanf("%d%d", &n, &m); for (int i = 1; i <= n; i++){ scanf("%d", &val[i]); } Build(1, n, 1); for (int i = 1; i <= m; i++){ int tpe, l, r, x; scanf("%d%d%d", &tpe, &l, &r); if (tpe == 1){ Modify(l, r, 1); } else if (tpe == 2){ scanf("%d", &x); Change(l, r, x, 1); } else{ printf("%lld\n", Query(l, r, 1)); } } } //#ifdef LOCAL_TIME // cout << "[Finished in " << clock() - start << " ms]" << endl; //#endif return 0; }
以上是关于HDU 5634 线段树的主要内容,如果未能解决你的问题,请参考以下文章