HDU 5634 线段树
Posted scaulok
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了HDU 5634 线段树相关的知识,希望对你有一定的参考价值。
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5634
题意:给出 n 个数,有三种操作,把区间的 ai 变为 φ(ai);把区间的 ai 变为 x;查询区间和。
题解:因为一个数由 ai 变为 φ(ai)在 log 次之后会变为 1 并且一直都为 1,考虑在没有第二种操作的情况下,只需要暴力修改记录区间最大值是否大于 1 即可。在加入第二个操作之后,可以发现对区间进行修改的话,一个区间内的数都是相同的,进行第一个操作可以对整个区间进行操作,故可以用线段树多记录一个区间内的数是否相同即可。
1 #include <bits/stdc++.h> 2 using namespace std; 3 #define ll long long 4 #define ull unsigned long long 5 #define mst(a,b) memset((a),(b),sizeof(a)) 6 #define mp(a,b) make_pair(a,b) 7 #define pi acos(-1) 8 #define pii pair<int,int> 9 #define pb push_back 10 const int INF = 0x3f3f3f3f; 11 const double eps = 1e-6; 12 const int MAXN = 3e5 + 10; 13 const int MAXM = 1e7 + 10; 14 const ll mod = 1e9 + 7; 15 16 bool check[MAXM]; 17 int phi[MAXM], prime[MAXM / 10], tot; 18 19 void init(int N) { 20 tot = 0; 21 phi[1] = 1; 22 for(int i = 2; i <= N; i++) { 23 if(!check[i]) { 24 prime[tot++] = i; 25 phi[i] = i - 1; 26 } 27 for(int j = 0; j < tot; j++) { 28 if(i * prime[j] > N) break; 29 check[i * prime[j]] = true; 30 if(i % prime[j] == 0) { 31 phi[i * prime[j]] = phi[i] * prime[j]; 32 break; 33 } else phi[i * prime[j]] = phi[i] * (prime[j] - 1); 34 } 35 } 36 } 37 38 int a[MAXN],num[MAXN<<2]; 39 ll sum[MAXN<<2]; 40 41 void pushup(int rt) { 42 sum[rt] = sum[rt<<1] + sum[rt<<1|1]; 43 if(num[rt<<1] == num[rt<<1|1]) num[rt] = num[rt<<1]; 44 else num[rt] = 0; 45 // num[rt] = (num[rt<<1] == num[rt<<1|1]) ? num[rt] : 0; 46 } 47 48 void build(int rt,int l,int r) { 49 if(l == r) { 50 sum[rt] = num[rt] = a[l]; 51 return ; 52 } 53 int mid = (l + r) >> 1; 54 build(rt<<1,l,mid); 55 build(rt<<1|1,mid + 1,r); 56 pushup(rt); 57 } 58 59 void pushdown(int rt,int l,int r) { 60 if(num[rt]) { 61 int mid = (l + r) >> 1; 62 num[rt<<1] = num[rt<<1|1] = num[rt]; 63 sum[rt<<1] = 1ll * num[rt<<1] * (mid - l + 1); 64 sum[rt<<1|1] = 1ll * num[rt<<1|1] * (r - mid); 65 num[rt] = 0; 66 } 67 } 68 69 void update1(int rt,int l,int r,int ql,int qr) { 70 if(ql > qr) return ; 71 if(num[rt] && l == ql && r == qr) { 72 num[rt] = phi[num[rt]]; 73 sum[rt] = 1ll * num[rt] * (r - l + 1); 74 return ; 75 } 76 pushdown(rt,l,r); 77 int mid = (l + r) >> 1; 78 if(qr <= mid) update1(rt<<1,l,mid,ql,qr); 79 else if(ql > mid) update1(rt<<1|1,mid + 1,r,ql,qr); 80 else { 81 update1(rt<<1,l,mid,ql,mid); 82 update1(rt<<1|1,mid + 1,r,mid + 1,qr); 83 } 84 pushup(rt); 85 } 86 87 void update2(int rt,int l,int r,int ql,int qr,int val) { 88 if(ql > qr) return ; 89 if(l == ql && r == qr) { 90 num[rt] = val; 91 sum[rt] = 1ll * num[rt] * (r - l + 1); 92 return ; 93 } 94 pushdown(rt,l,r); 95 int mid = (l + r) >> 1; 96 if(qr <= mid) update2(rt<<1,l,mid,ql,qr,val); 97 else if(ql > mid) update2(rt<<1|1,mid + 1,r,ql,qr,val); 98 else { 99 update2(rt<<1,l,mid,ql,mid,val); 100 update2(rt<<1|1,mid + 1,r,mid + 1,qr,val); 101 } 102 pushup(rt); 103 } 104 105 ll query(int rt,int l,int r,int ql,int qr) { 106 if(ql == l && qr == r) return sum[rt]; 107 pushdown(rt,l,r); 108 int mid = (l + r) >> 1; 109 if(qr <= mid) return query(rt<<1,l,mid,ql,qr); 110 else if(ql > mid) return query(rt<<1|1,mid + 1,r,ql,qr); 111 else return query(rt<<1,l,mid,ql,mid) + query(rt<<1|1,mid + 1,r,mid + 1,qr); 112 } 113 114 int main() { 115 #ifdef local 116 freopen("data.txt", "r", stdin); 117 // freopen("data.txt", "w", stdout); 118 #endif 119 init(1e7); 120 int t; 121 scanf("%d",&t); 122 while(t--) { 123 int n,m; 124 scanf("%d%d",&n,&m); 125 for(int i = 1; i <= n; i++) scanf("%d",&a[i]); 126 build(1,1,n); 127 while(m--) { 128 int op,l,r,x; 129 scanf("%d",&op); 130 if(op == 1) { 131 scanf("%d%d",&l,&r); 132 update1(1,1,n,l,r); 133 } else if(op == 2) { 134 scanf("%d%d%d",&l,&r,&x); 135 update2(1,1,n,l,r,x); 136 } else if(op == 3) { 137 scanf("%d%d",&l,&r); 138 printf("%lld ",query(1,1,n,l,r)); 139 } 140 } 141 } 142 return 0; 143 }
以上是关于HDU 5634 线段树的主要内容,如果未能解决你的问题,请参考以下文章