BZOJ4373 算术天才⑨与等差数列 【线段树】*
BZOJ4373 算术天才⑨与等差数列
Description
算术天才⑨非常喜欢和等差数列玩耍。
有一天,他给了你一个长度为n的序列,其中第i个数为a[i]。
他想考考你,每次他会给出询问l,r,k,问区间[l,r]内的数从小到大排序后能否形成公差为k的等差数列。
当然,他还会不断修改其中的某一项。
为了不被他鄙视,你必须要快速并正确地回答完所有问题。
注意:只有一个数的数列也是等差数列。
Input
第一行包含两个正整数n,m(1<=n,m<=300000),分别表示序列的长度和操作的次数。
第二行包含n个整数,依次表示序列中的每个数ai。
接下来m行,每行一开始为一个数op,
若op=1,则接下来两个整数x,y(1<=x<=n,0<=y<=10^9),表示把a[x]修改为y。
若op=2,则接下来三个整数l,r,k(1<=l<=r<=n,0<=k<=10^9),表示一个询问。
在本题中,x,y,l,r,k都是经过加密的,都需要异或你之前输出的Yes的个数来进行解密。
Output
输出若干行,对于每个询问,如果可以形成等差数列,那么输出Yes,否则输出No。
Sample Input
5 3
1 3 2 5 6
2 1 5 1
1 5 4
2 1 5 1
Sample Output
No
满足等差数列的条件:
1.gcd(ai−ai+1)%k=0(l≤i<r)
2.max(ai)−min(ai)=(r−l)∗k(l≤i≤r)
3.区间内没有重复的数3.区间内没有重复的数3.区间内没有重复的数
对于第一个,我们可以用线段树维护相邻两点值的差的gcd
对于第二个,直接维护最大最小值
对于第三个,我们记录区间内所有数上一次出现的位置,取max,如果这个位置大于l就重复了
然后对于上一次出现的数,可以直接暴力开set,大概只需要n∗2个set就够用了
然后别挥霍内存就可以了
还有一个需要注意
就是k=0的情况要特判掉
1 #include<bits/stdc++.h> 2 using namespace std; 3 #define N 300001 4 #define LD (t<<1) 5 #define RD (t<<1|1) 6 int t1; 7 map<int,int> mp; 8 set<int> s[N<<1]; 9 int n,m,val[N],pre[N]; 10 struct Node{int gcd,minv,maxv,pre;}T[N<<2],tmp1,tmp2,res; 11 int t2; 12 int read(){ 13 int ans=0,w=1;char c=getchar(); 14 while(!isdigit(c)&&c!='-')c=getchar(); 15 if(c=='-')w=-1,c=getchar(); 16 while(isdigit(c))ans=(ans<<1)+(ans<<3)+c-'0',c=getchar(); 17 return ans*w; 18 } 19 int gcd(int a,int b){return b?gcd(b,a%b):a;} 20 Node merge(Node l,Node r){ 21 res.gcd=gcd(l.gcd,r.gcd); 22 res.maxv=max(l.maxv,r.maxv); 23 res.minv=min(l.minv,r.minv); 24 res.pre=max(l.pre,r.pre); 25 return res; 26 } 27 void build(int t,int l,int r){ 28 if(l>r)return; 29 if(l==r){ 30 T[t].gcd=abs(val[l]-val[l+1]); 31 T[t].minv=T[t].maxv=val[l]; 32 T[t].pre=pre[l]; 33 return; 34 } 35 int mid=(l+r)>>1; 36 build(LD,l,mid); 37 build(RD,mid+1,r); 38 T[t]=merge(T[LD],T[RD]); 39 } 40 void modify(int t,int l,int r,int pos){ 41 if(l==r){ 42 T[t].gcd=abs(val[l]-val[l+1]); 43 T[t].minv=T[t].maxv=val[l]; 44 T[t].pre=pre[l]; 45 return; 46 } 47 int mid=(l+r)>>1; 48 if(pos<=mid)modify(LD,l,mid,pos); 49 else modify(RD,mid+1,r,pos); 50 T[t]=merge(T[LD],T[RD]); 51 } 52 Node query(int t,int l,int r,int L,int R){ 53 if(L<=l&&r<=R)return T[t]; 54 int mid=(l+r)>>1; 55 if(R<=mid)return query(LD,l,mid,L,R); 56 if(L>mid)return query(RD,mid+1,r,L,R); 57 return merge(query(LD,l,mid,L,mid),query(RD,mid+1,r,mid+1,R)); 58 } 59 int main(){ 60 freopen("4373.in","r",stdin); 61 freopen("4373.out","w",stdout); 62 scanf("%d%d",&n,&m); 63 int cnt=0; 64 for(int i=1;i<=n;i++){ 65 val[i]=read(); 66 if(!mp[val[i]]){ 67 mp[val[i]]=++cnt; 68 s[cnt].insert(0); 69 s[cnt].insert(n+1); 70 s[cnt].insert(i); 71 pre[i]=0; 72 }else{ 73 s[mp[val[i]]].insert(i); 74 pre[i]=*--(s[mp[val[i]]].lower_bound(i)); 75 } 76 } 77 val[n+1]=val[n]; 78 build(1,1,n); 79 int las=0; 80 while(m--){ 81 int op=read(); 82 if(op==1){ 83 int x=read()^las,y=read()^las; 84 int t=mp[val[x]]; 85 int tmp=*s[t].upper_bound(x); 86 if(tmp!=n+1){ 87 pre[tmp]=pre[x]; 88 modify(1,1,n,tmp); 89 } 90 s[t].erase(x); 91 if(!mp[y]){ 92 mp[y]=++cnt; 93 s[cnt].insert(0); 94 s[cnt].insert(n+1); 95 s[cnt].insert(x); 96 pre[x]=0; 97 }else{ 98 s[mp[y]].insert(x); 99 pre[x]=*--s[t].lower_bound(x); 100 } 101 t=mp[y]; 102 tmp=*s[t].upper_bound(x); 103 if(tmp!=n+1){ 104 pre[tmp]=x; 105 modify(1,1,n,x); 106 } 107 if(x==n)val[n+1]=y; 108 val[x]=y; 109 modify(1,1,n,x); 110 if(x>1)modify(1,1,n,x-1); 111 }else{ 112 int l=read()^las,r=read()^las,k=read()^las; 113 if(l==r){printf("Yes\n");++las;continue;} 114 tmp1=query(1,1,n,l,r-1); 115 tmp2=merge(tmp1,query(1,1,n,r,r)); 116 if(!k){ 117 if(tmp2.minv==tmp2.maxv)++las,printf("Yes\n"); 118 else printf("No\n"); 119 continue; 120 } 121 if(tmp1.gcd%k){printf("No\n");;continue;} 122 if(tmp2.pre>=l){printf("No\n");continue;} 123 if(tmp2.maxv-tmp2.minv!=(r-l)*k){printf("No\n");continue;} 124 las++; 125 printf("Yes\n"); 126 } 127 } 128 printf("\n"); 129 return 0; 130 }