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 }