bzoj4373 算术天才⑨与等差数列——线段树+set
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=4373
一个区间有以 k 为公差的数列,有3个条件:
1.区间 mx - mn = (r-l) * k;
2.差分数组的 gcd 是 k 的倍数;
3.没有重复出现的数;
其中1,2都可以用线段树维护,3用 set 维护每个数上一个出现的位置即可;
模仿TJ写的:https://blog.csdn.net/neither_nor/article/details/52461940
对 set 更熟悉了,细节还蛮多的。
代码如下:
#include<iostream> #include<cstdio> #include<cstring> #include<set> #include<map> using namespace std; int const maxn=3e5+5; int n,m,a[maxn],key,tot,pre[maxn]; map<int,int>h; set<int>s[maxn<<1]; int gcd(int a,int b){return b?gcd(b,a%b):a;} int ab(int x){return x>0?x:-x;} struct N{ int mx,mn,fro,g; friend N operator + (N x,N y) { N ret; ret.mx=max(x.mx,y.mx); ret.mn=min(x.mn,y.mn); ret.fro=max(x.fro,y.fro); ret.g=gcd(x.g,y.g); return ret;//! } }t[maxn<<2]; void build(int x,int l,int r) { if(l==r) { t[x].mn=t[x].mx=a[l]; t[x].g=ab(a[l+1]-a[l]); t[x].fro=pre[l]; return; } int mid=((l+r)>>1); build(x<<1,l,mid); build(x<<1|1,mid+1,r); t[x]=t[x<<1]+t[x<<1|1]; } void update(int x,int l,int r,int p) { if(l==r) { t[x].mn=t[x].mx=a[l]; t[x].g=ab(a[l+1]-a[l]); t[x].fro=pre[l]; return; } int mid=((l+r)>>1); if(p<=mid)update(x<<1,l,mid,p); else update(x<<1|1,mid+1,r,p); t[x]=t[x<<1]+t[x<<1|1]; } N query(int x,int l,int r,int L,int R) { if(l>=L&&r<=R)return t[x]; int mid=((l+r)>>1); if(mid<L)return query(x<<1|1,mid+1,r,L,R); else if(mid>=R)return query(x<<1,l,mid,L,R); else return query(x<<1,l,mid,L,R)+query(x<<1|1,mid+1,r,L,R); } int main() { scanf("%d%d",&n,&m); for(int i=1;i<=n;i++) { scanf("%d",&a[i]); if(!h[a[i]]) { h[a[i]]=++tot; s[tot].insert(0); s[tot].insert(n+1); } int tmp=h[a[i]]; s[tmp].insert(i); pre[i]=*--(s[tmp].insert(i).first);// } a[n+1]=a[n];//! build(1,1,n); for(int i=1,op,x,y,l,r,k;i<=m;i++) { scanf("%d",&op); if(op==1) { scanf("%d%d",&x,&y); x^=key; y^=key; int tmp,nxt,pr; tmp=h[a[x]]; nxt=*s[tmp].upper_bound(x); if(nxt!=n+1) { pre[nxt]=pre[x]; update(1,1,n,nxt); } s[tmp].erase(x); if(!h[y])// { h[y]=++tot; s[tot].insert(0); s[tot].insert(n+1); } tmp=h[y]; s[tmp].insert(x); nxt=*s[tmp].upper_bound(x); pre[x]=*--s[tmp].lower_bound(x); if(nxt!=n+1) { pre[nxt]=x; update(1,1,n,nxt); } a[x]=y; update(1,1,n,x); if(x!=1)update(1,1,n,x-1);// } if(op==2) { scanf("%d%d%d",&l,&r,&k); l^=key; r^=key; k^=key; if(l==r){key++; printf("Yes\n"); continue;} N tmpp=query(1,1,n,l,r-1);// N tmp=tmpp+query(1,1,n,r,r);// if(k==0) { if(tmp.mx==tmp.mn)key++,printf("Yes\n"); else printf("No\n"); continue; } if(tmp.fro<l && tmp.mx==k*(r-l)+tmp.mn && tmpp.g%k==0)//tmpp! key++,printf("Yes\n"); else printf("No\n"); } } return 0; }