HDU5634 Rikka with Phi 线段树

  1 // HDU5634 Rikka with Phi 线段树
  2 // 思路:操作1的时候,判断一下当前区间是不是每个数都相等,在每个数相等的区间上操作。相当于lazy,不必更新到底。
  3
  4
  5 #include <bits/stdc++.h>
  6 using namespace std;
  7 #define clc(a,b) memset(a,b,sizeof(a))
  8 #define inf 0x3f3f3f3f
  9 #define lson l,mid,rt<<1
 10 #define rson mid+1,r,rt<<1|1
 11 const int N = 300010;
 12 const int MOD = 1e9+7;
 13 #define LL long long
 14 double const pi = acos(-1);
 15 void fre() {
 16     freopen("in.txt","r",stdin);
 17 }
 18 // inline int r() {
 19 //     int x=0,f=1;char ch=getchar();
 20 //     while(ch>‘9‘||ch<‘0‘) {if(ch==‘-‘) f=-1;ch=getchar();}
 21 //     while(ch>=‘0‘&&ch<=‘9‘) { x=x*10+ch-‘0‘;ch=getchar();}return x*f;
 22 // }
 23 const int MAXM=1e7+10;
 24 LL euler[10000010];
 25 int a[N];
 26 void Geteuler()
 27 {
 28     memset(euler, 0, sizeof(euler));
 29     euler[1] = 1;
 30     for(LL i = 2; i < MAXM; i++) if(!euler[i])
 31         for(LL j = i; j < MAXM; j += i){
 32             if(!euler[j]) euler[j] = j;
 33             euler[j] = euler[j] / i * (i-1);
 34         }
 35 }
 36
 37 struct tree{
 38     int l,r;
 39     LL sum,lazy;
 40 }t[N<<2];
 41
 42 void pushup(int rt){
 43     t[rt].sum=t[rt<<1].sum+t[rt<<1|1].sum;
 44     if(t[rt<<1].lazy==t[rt<<1|1].lazy) t[rt].lazy=t[rt<<1].lazy;
 45     else t[rt].lazy=0;
 46 }
 47
 48 void pushdown(int rt){
 49     if(t[rt].lazy){
 50         t[rt<<1].lazy=t[rt<<1|1].lazy=t[rt].lazy;
 51         t[rt<<1].sum=(t[rt<<1].r-t[rt<<1].l+1)*t[rt<<1].lazy;
 52         t[rt<<1|1].sum=(t[rt<<1|1].r-t[rt<<1|1].l+1)*t[rt<<1|1].lazy;
 53         t[rt].lazy=0;
 54     }
 55 }
 56 void build(int rt,int x,int y){
 57     t[rt].l=x;
 58     t[rt].r=y;
 59     if(x==y){
 60         t[rt].sum=a[x];
 61         t[rt].lazy=a[x];
 62         return;
 63     }
 64     int mid=(x+y)>>1;
 65     build(rt<<1,x,mid);
 66     build(rt<<1|1,mid+1,y);
 67     pushup(rt);
 68 }
 69
 70 void update1(int rt,int x,int y){
 71     if(t[rt].lazy&&t[rt].l==x&&t[rt].r==y){
 72         t[rt].sum=(t[rt].r-t[rt].l+1)*euler[t[rt].lazy];
 73         t[rt].lazy=euler[t[rt].lazy];
 74         return;
 75     }
 76     pushdown(rt);
 77     int mid=(t[rt].l+t[rt].r)>>1;
 78     if(y<=mid) update1(rt<<1,x,y);
 79     else if(x>mid) update1(rt<<1|1,x,y);
 80     else {
 81         update1(rt<<1,x,mid);
 82         update1(rt<<1|1,mid+1,y);
 83     }
 84     pushup(rt);
 85 }
 86
 87 void update2(int rt,int x,int y,int z){
 88     if(t[rt].l==x&&t[rt].r==y){
 89         t[rt].lazy=z;
 90         t[rt].sum=1LL*z*(t[rt].r-t[rt].l+1);
 91         return;
 92     }
 93     pushdown(rt);
 94     int mid=(t[rt].l+t[rt].r)>>1;
 95     if(y<=mid) update2(rt<<1,x,y,z);
 96     else if(x>mid) update2(rt<<1|1,x,y,z);
 97     else {
 98         update2(rt<<1,x,mid,z);
 99         update2(rt<<1|1,mid+1,y,z);
100     }
101     pushup(rt);
102 }
103
104 LL  query(int rt,int x,int y){
105     if(t[rt].l==x&&t[rt].r==y){
106         return t[rt].sum;
107     }
108     pushdown(rt);
109     int mid=(t[rt].l+t[rt].r)>>1;
110     if(y<=mid) return query(rt<<1,x,y);
111     else if(x>mid) return query(rt<<1|1,x,y);
112     else{
113         return query(rt<<1,x,mid)+query(rt<<1|1,mid+1,y);
114     }
115 }
116 int main(){
117     // fre();
118     Geteuler();
119     int T;
120     scanf("%d",&T);
121     while(T--){
122         int n,m;
123         scanf("%d%d",&n,&m);
124         for(int i=1;i<=n;i++) scanf("%d",&a[i]);
125         build(1,1,n);
126         while(m--){
127             int op,x,y,z;
128             scanf("%d%d%d",&op,&x,&y);
129             if(op==1) update1(1,x,y);
130             else if(op==2) {
131                 scanf("%d",&z);
132                 update2(1,x,y,z);
133             }
134             else {
135                 // cout<<"sdf"<<endl;
136                 LL ans=query(1,x,y);
137                 printf("%I64d\n",ans);
138             }
139         }
140     }
141     return 0;
142 }
时间: 2024-10-21 15:09:45

HDU5634 Rikka with Phi 线段树的相关文章

HDU 5634 Rikka with Phi 线段树

题意:bc round 73 div1 D 中文题面 分析:注意到10^7之内的数最多phi O(log(n))次就会变成1, 因此可以考虑把一段相同的不为1的数缩成一个点,用平衡树来维护. 每次求phi的时候就在平衡树上取出这个区间然后暴力求phi,如果一段数变成了1, 就在平衡树里面删掉它,最后统计答案的时候只要把区间中被删去的1加回答案即可, 时间复杂度O((n + m)logn) 注:平衡树,写起来麻烦(然后其实我也不会写) 但是题解当中说把一段相同的数缩成一个点,就很好 所以用线段树,

2016暑假多校联合---Rikka with Sequence (线段树)

2016暑假多校联合---Rikka with Sequence (线段树) Problem Description As we know, Rikka is poor at math. Yuta is worrying about this situation, so he gives Rikka some math tasks to practice. There is one of them: Yuta has an array A with n numbers. Then he make

HDU 6089 Rikka with Terrorist (线段树)

题目链接 http://acm.hdu.edu.cn/showproblem.php?pid=6089 题解 这波强行维护搞得我很懵逼... 扫描线,只考虑每个点能走到左上方(不包括正上方,但包括正左方)的哪些点,然后旋转四次坐标系处理 所有询问和操作点按照先\(x\)后\(y\)坐标的顺序排序,然后枚举每一行,按\(y\)从小到大的顺序枚举这一行每个点 对于一个询问点找出前面最后一个操作点,那么要求的就是一个矩形减去一个区间内所有后缀最大值的和 然后这个东西可以用线段树直接维护,记录个区间最大

HDU 5828 Rikka with Sequence (线段树+剪枝优化)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5828 给你n个数,三种操作.操作1是将l到r之间的数都加上x:操作2是将l到r之间的数都开方:操作3是求出l到r之间的和. 操作1和3就不说了,关键是开方操作. 一个一个开方,复杂度太高,无疑会T.所以我们来剪枝一下. 我们可以观察,这里一个数最多开方4,5次(loglogx次)就会到1,所以要是一段区间最大值为1的话,就不需要递归开方下去了.这是一个剪枝. 如果一段区间的数都是一样大小(最大值等于

【HDU 5828】Rikka with Sequence(线段树)

[HDU 5828]Rikka with Sequence(线段树) Rikka with Sequence Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)Total Submission(s): 2311    Accepted Submission(s): 391 Problem Description As we know, Rikka is poor at math.

HDU 6681 Rikka with Cake(扫描线、动态开点线段树)

http://acm.hdu.edu.cn/showproblem.php?pid=6681 题意 在矩形区域内有k条射线,问这些射线将矩形分成了多少区域 题解 容易发现答案为所有射线交点个数. 按y从排序扫描矩形区域,动态开点线段树维护区间内竖线的个数,由于n,m范围较大,需要离散化处理,但这样比较麻烦且此题空间足够所以建议用动态开点. 1 #define bug(x) cout<<#x<<" is "<<x<<endl 2 #defi

HDU 5634 Rikka with Phi

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5634 -------------------------------------------------------------------------------------------- 官方题解上给的是用平衡树写 不过用类似的思路 也是可以用线段树去写的 操作$2$区间赋为相同值可以直接按照常规的线段树的题目去写 操作$1$是只减不增的 而且最多$log$次会减少到$1$ 所以大量使用$1$操

HDU5152 线段树 + 数论

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5152 ,线段树区间更新 + 点更新 + 数论知识(数论是重点QAQ),好题值得一做. BestCoder Round #24的C题,一道神题,不得不说,出题人的数论学的很好,很多人都没想到2333333不是素数的问题,当时全场爆零.我今天下午开始研究这道题,后来看了好久的标程才懂,惭愧. 一共有两个操作一个询问:1.询问[l , r]区间里的值的和; 2.将点x的值a[x]赋为2a[x]; 3.将区

loj1370(欧拉函数+线段树)

传送门:Bi-shoe and Phi-shoe 题意:给出多个n(1<=n<=1e6),求满足phi(x)>=n的最小的x之和. 分析:先预处理出1~1e6的欧拉函数,然后建立一颗线段树维护最大值,对于每个n询问大于等于n的最左边下标. #pragma comment(linker,"/STACK:1024000000,1024000000") #include <cstdio> #include <cstring> #include <