BZOJ 4373算术天才⑨与等差数列(线段树)

题意:
给你一个长度为n的序列,有m个操作,写一个程序支持以下两个操作: 

1. 修改一个值 

2. 给出三个数l,r,k,

询问:如果把区间[l,r]的数从小到大排序,能否形成公差为k的等差数列。
n,m≤300000 0≤k,a[i]≤109

题解

这题坑我很久。

一眼望去这题不可作。(倒是想到维护最小值和最大值。)

然后翻了题解。发现我的想法和题解差不多。

直接维护区间等差数列显然很难,那么考虑一下:如果区间[l,r] (l < r)排序后能形成公差为k(k>0)的等差数列,要满足什么条件?

  1. 很显然,假设min是区间最小值,max是区间最大值,那么 min+k(r−l)=max

  2. 区间相邻两个数之差的绝对值的gcd=k

3. 区间没有重复的数

前两个条件 线段树直接维护就好

第三个条件:

对于每个权值开个set,值为位置(离散化标号)

然后维护一个pre[i],表示当前a[i]这个值,在i前面最后一次出现的位置。那么满足第3个条件,当且仅当区间[l,r]的pre的最大值小于l。这个也是用线段树维护。

然后看修改操作:在set上找前一个数、后一个数,然后修改相应的值


 

然后发现不会用set求前驱后继。然后花了几个小时学。

(一开始翻的博客都只介绍set的函数。然后翻到一篇讲求前去后继的,一眼扫完就会了,看好博客是多么重要啊)

然后这个iter是个迭代器。*iter是第一个比x大的数的实际下标,也就是后继的下标(如果iter是q.end()说明没有后继)

然后这个it也是个迭代器。*it是第一个大于等于x的数的实际下标。然后it--不是减实际的下标,而是使set中的下标。

假如*it是第一个比x小的数的下标,it--后*it就是第二个比x小的数的实际下标。

所以把x插入set后用上面的式子求出it,it--后*it就是x的前驱的实际下标

  1 #include<cstdio>
  2 #include<iostream>
  3 #include<cmath>
  4 #include<cstring>
  5 #include<algorithm>
  6 #include<set>
  7 #include<map>
  8 using namespace std;
  9 const int N=300010;
 10 set<int>q[N<<1];
 11 map<int,int> ma;
 12 int a[N],pre[N],n,m,num,cnt;
 13 int gcd(int x,int y){
 14     if(y==0)return x;
 15     if(x==0)return y;
 16     else return gcd(y,x%y);
 17 }
 18 struct tree{
 19     int l,r,mx,mn,gc,mnp,ln,rn;
 20 }tr[N<<2];
 21 void update(int now){
 22     tr[now].ln=tr[now*2].ln;
 23     tr[now].rn=tr[now*2+1].rn;
 24     tr[now].gc=abs(tr[now*2].rn-tr[now*2+1].ln);
 25     tr[now].gc=gcd(tr[now].gc,gcd(tr[now*2].gc,tr[now*2+1].gc));
 26     tr[now].mn=min(tr[now*2].mn,tr[now*2+1].mn);
 27     tr[now].mx=max(tr[now*2].mx,tr[now*2+1].mx);
 28     tr[now].mnp=max(tr[now*2].mnp,tr[now*2+1].mnp);
 29 }
 30 void build(int l,int r,int now){
 31     tr[now].l=l;tr[now].r=r;
 32     if(l==r){
 33         tr[now].mx=tr[now].mn=tr[now].ln=tr[now].rn=a[l];
 34         tr[now].mnp=pre[l];
 35         return;
 36     }
 37     int mid=(tr[now].l+tr[now].r)>>1;
 38     build(l,mid,now*2);
 39     build(mid+1,r,now*2+1);
 40     update(now);
 41 }
 42 void change(int x,int now){
 43     if(tr[now].l==tr[now].r){
 44         tr[now].mx=tr[now].mn=tr[now].ln=tr[now].rn=a[tr[now].l];
 45         tr[now].mnp=pre[tr[now].l];
 46         return;
 47     }
 48     int mid=(tr[now].l+tr[now].r)>>1;
 49     if(x>mid)change(x,now*2+1);
 50     else change(x,now*2);
 51     update(now);
 52 }
 53 int getmin(int l,int r,int now){
 54     if(tr[now].l==l&&tr[now].r==r){
 55         return tr[now].mn;
 56     }
 57     int mid=(tr[now].l+tr[now].r)>>1;
 58     if(l>mid)return getmin(l,r,now*2+1);
 59     else if(r<=mid)return getmin(l,r,now*2);
 60     else {
 61         return min(getmin(l,mid,now*2),getmin(mid+1,r,now*2+1));
 62     }
 63 }
 64 int getmax(int l,int r,int now){
 65     if(tr[now].l==l&&tr[now].r==r){
 66         return tr[now].mx;
 67     }
 68     int mid=(tr[now].l+tr[now].r)>>1;
 69     if(l>mid)return getmax(l,r,now*2+1);
 70     else if(r<=mid)return getmax(l,r,now*2);
 71     else {
 72         return max(getmax(l,mid,now*2),getmax(mid+1,r,now*2+1));
 73     }
 74 }
 75 int getgcd(int l,int r,int now){
 76     if(tr[now].l==l&&tr[now].r==r){
 77         return tr[now].gc;
 78     }
 79     int mid=(tr[now].l+tr[now].r)>>1;
 80     if(l>mid)return getgcd(l,r,now*2+1);
 81     else if(r<=mid)return getgcd(l,r,now*2);
 82     else {
 83         return gcd(gcd(getgcd(l,mid,now*2),getgcd(mid+1,r,now*2+1)),abs(tr[now*2].rn-tr[now*2+1].ln));
 84     } 
 85 }
 86 int getpre(int l,int r,int now){
 87     if(tr[now].l==l&&tr[now].r==r){
 88         return tr[now].mnp;
 89     }
 90     int mid=(tr[now].l+tr[now].r)>>1;
 91     if(l>mid)return getpre(l,r,now*2+1);
 92     else if(r<=mid)return getpre(l,r,now*2);
 93     else {
 94         return max(getpre(l,mid,now*2),getpre(mid+1,r,now*2+1));
 95     }
 96 }
 97 int main(){
 98     scanf("%d%d",&n,&m);
 99     for(int i=1;i<=n;i++){
100         scanf("%d",&a[i]);
101         if(ma[a[i]]==0){
102             ma[a[i]]=++num;
103             q[ma[a[i]]].insert(i);
104         }
105         else{       
106             q[ma[a[i]]].insert(i);
107             set<int>::iterator it=q[ma[a[i]]].lower_bound(i);
108             it--;
109             pre[i]=*it;
110         }
111     }
112     build(1,n,1);
113     for(int i=1;i<=m;i++){
114         int k;
115         scanf("%d",&k);
116         if(k==1){
117             int x,y;
118             scanf("%d%d",&x,&y);
119             x^=cnt;y^=cnt;
120             set<int>::iterator iter=q[ma[a[x]]].upper_bound(x);
121             if(iter!=q[ma[a[x]]].end()){
122                 pre[*iter]=pre[x];
123                 change(*iter,1);
124             }
125             q[ma[a[x]]].erase(x);
126             a[x]=y;
127             if(ma[y]==0){
128                 ma[y]=++num;
129                 q[ma[y]].insert(x);
130                 pre[x]=0;
131             }
132             else{
133                 q[ma[y]].insert(x);
134                 set<int>::iterator it=q[ma[y]].lower_bound(x);
135                 if(it!=q[ma[y]].begin()){
136                     it--;
137                     pre[i]=*it;
138                 }
139                 iter=q[ma[y]].upper_bound(x);
140                 if(iter!=q[ma[y]].end()){
141                     pre[*iter]=x;
142                     change(*iter,1);
143                 }
144             }
145             change(x,1);
146         }
147         else{
148             int l;int r;int x;
149             scanf("%d%d%d",&l,&r,&x);
150             l^=cnt;r^=cnt;x^=cnt;
151             int mn=getmin(l,r,1);
152             int mx=getmax(l,r,1);
153             if(l==r){
154                 printf("Yes\n");
155                 cnt++;
156                 continue;
157             }
158             if(x==0){
159                 if(mn==mx){
160                     printf("Yes\n");
161                     cnt++;  
162                 }
163                 else printf("No\n");
164                 continue;
165             }
166             if(mn+(r-l)*x!=mx){
167                 printf("No\n");
168                 continue;
169             }
170             int GCD=getgcd(l,r,1);
171             if(GCD%x!=0){
172                 printf("No\n");
173                 continue;
174             }
175             int PRE=getpre(l,r,1);
176             if(PRE>=l){
177                 printf("No\n");
178                 continue;
179             }
180             printf("Yes\n");
181             cnt++;
182         }
183     }
184     return 0;
185 }
View Code

 

posted @ 2018-08-06 17:23  Xu-daxia  阅读(233)  评论(0编辑  收藏  举报