codeforces 914 D Bash and a Tough Math Puzzle

 1 #include<iostream>
 2 #include<cstring>
 3 #include<cstdio>
 4 #include<algorithm>
 5 #include<cstdio>
 6 using namespace std;
 7 const int N=500100;
 8 int n,a[N],m;
 9 struct tree{
10     int l,r,gcd;
11 }tr[N*5];
12 int gcd(int x,int y){
13     if(y==0)return x;
14     else return gcd(y,x%y);
15 }
16 void build(int l,int r,int now){
17     tr[now].l=l;tr[now].r=r;
18     if(l==r){
19         tr[now].gcd=a[l];
20         return;
21     }
22     int mid=(l+r)>>1;
23     build(l,mid,now*2);
24     build(mid+1,r,now*2+1);
25     tr[now].gcd=gcd(tr[now*2].gcd,tr[now*2+1].gcd);
26 }
27 void change(int x,int y,int now){
28 //    cout<<tr[now].l<<" "<<tr[now].r<<" "<<x<<endl;
29     if(tr[now].l==x&&tr[now].r==x){
30         tr[now].gcd=y;
31         return ;
32     }
33     int mid=(tr[now].l+tr[now].r)>>1;
34     if(x>mid)change(x,y,now*2+1);
35     else change(x,y,now*2);
36     tr[now].gcd=gcd(tr[now*2].gcd,tr[now*2+1].gcd);
37 }
38 int check(int l,int r,int x,int now){
39     if(tr[now].gcd%x==0)return 0;
40     if(tr[now].l==l&&tr[now].r==r){
41         if(l==r)return 1;
42         if(tr[now*2].gcd%x==0)return check(tr[now*2+1].l,tr[now*2+1].r,x,now*2+1);
43         if(tr[now*2+1].gcd%x==0)return check(tr[now*2].l,tr[now*2].r,x,now*2);
44         return 2;
45     }
46     int mid=(tr[now].l+tr[now].r)>>1;
47     if(l>mid)return check(l,r,x,now*2+1);
48     else if(r<=mid)return check(l,r,x,now*2);
49     else{
50         return check(l,mid,x,now*2)+check(mid+1,r,x,now*2+1);
51     } 
52 }
53 int main(){
54     scanf("%d",&n);
55     for(int i=1;i<=n;i++){
56         scanf("%d",&a[i]);
57     }
58     build(1,n,1);
59     scanf("%d",&m);
60     for(int i=1;i<=m;i++){
61         int k;
62         scanf("%d",&k);
63         if(k==1){
64             int l,r,x;
65             scanf("%d%d%d",&l,&r,&x);
66             if(check(l,r,x,1)<=1)printf("YES\n");
67             else printf("NO\n");
68         }
69         else{
70             int x,y;
71             scanf("%d%d",&x,&y);
72             change(x,y,1);
73         }
74     }
75     return 0;
76 }
View Code

 

题意

•给出一段序列(1≤n≤5*105),两个操作(1≤q≤4*105)

•操作1 给出l,r,x

•求区间l-r的gcd,如果至多能改掉区间内的一个数,使gcd是x的倍数,那么输出YES,否则输出NO

•操作2 给出pos,x

•将序列中pos位置上的数字改为x

题解

线段树,维护区间的gcd

因为题目询问删除一个数,我们把整个区间分成两块,如果两边的gcd都是x的倍数显然是可以的,如果都不是gcd的倍数,就不行了,因为使两个gcd的gcd为x的倍数,这两个gcd应该都至少含有x因子。如果一个gcd是x的倍数,一个不是,那就递归处理不是的那个区间。

 

posted @ 2018-07-13 19:17  Xu-daxia  阅读(166)  评论(0编辑  收藏  举报