bzoj 4373 算术天才⑨与等差数列——线段树+set

题目:https://www.lydsy.com/JudgeOnline/problem.php?id=4373

能形成公差为k的等差数列的条件:mx-mn=k*(r-l) && 差分数组gcd为k  && 区间内没有重复的数。

这些都可以线段树维护。

那个“没有重复的数”需要给每个位置记下权值的pre,修改的时候需要找到它前面一个和后面一个。

用链表的话没法插入。可以给每个权值开一个set,就能用lower_bound了。

有些细节。重载运算符很方便。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<map>
#include<set>
using namespace std;
const int N=3e5+5,INF=1e9+5;
int n,m,c[N],ls[N<<1],rs[N<<1],tot,pre[N],lt,cnt;
map<int,int> mp;
set<int> s[N<<1];
int gcd(int a,int b){return b?gcd(b,a%b):a;}
int abss(int k){return k<0?-k:k;}
struct Node{
  int mx,mn,lst,g;
  Node(int a=0,int b=0,int l=0,int g=0):mx(a),mn(b),lst(l),g(g) {}
  Node operator+ (const Node &b)const
  {
    return Node(max(mx,b.mx),min(mn,b.mn),max(lst,b.lst),gcd(g,b.g));
  }
}a[N<<1];
void add(int x)
{
  mp[x]=++cnt;s[cnt].insert(0);s[cnt].insert(n+1);
}
void pshp(int cr)
{
  a[cr]=a[ls[cr]]+a[rs[cr]];
}
void build(int l,int r,int cr)
{
  if(l==r)
    {
      a[cr]=Node(c[l],c[l],pre[l],abss(c[l+1]-c[l]));return;
    }
  int mid=((l+r)>>1);
  ls[cr]=++tot;build(l,mid,ls[cr]);
  rs[cr]=++tot;build(mid+1,r,rs[cr]);
  pshp(cr);//!!!
}
void updt(int l,int r,int cr,int p)
{
  if(l==r)
    {
      a[cr]=Node(c[l],c[l],pre[l],abss(c[l+1]-c[l]));return;
    }
  int mid=((l+r)>>1);
  if(p<=mid)updt(l,mid,ls[cr],p);
  else updt(mid+1,r,rs[cr],p);
  pshp(cr);
}
Node query(int l,int r,int cr,int L,int R)
{
  if(l>=L&&r<=R)return a[cr];
  int mid=((l+r)>>1);
  if(L>mid)return query(mid+1,r,rs[cr],L,R);
  if(R<=mid)return query(l,mid,ls[cr],L,R);
  return query(l,mid,ls[cr],L,R)+query(mid+1,r,rs[cr],L,R);
}
int main()
{
  scanf("%d%d",&n,&m);
  for(int i=1;i<=n;i++)
    {
      scanf("%d",&c[i]);
      if(!mp[c[i]])add(c[i]);
      int t=mp[c[i]];
      pre[i]=*--s[t].lower_bound(i);
      s[t].insert(i);
    }
  a[n+1]=a[n];//?是为了让最后一个点的差分是0,使不影响吧 
  tot=1;build(1,n,1);
  int op,x,y;
  while(m--)
    {
      scanf("%d",&op);
      if(op==1)
    {
      scanf("%d%d",&x,&y);x^=lt;y^=lt;
      int t=mp[c[x]];
      int u=*--s[t].lower_bound(x),v=*s[t].upper_bound(x);
      if(v!=n+1)pre[v]=u,updt(1,n,1,v);//v!=n+1
      s[t].erase(x);
      if(!mp[y])add(y);t=mp[y];
      u=*--s[t].lower_bound(x);v=*s[t].upper_bound(x);
      if(v!=n+1)pre[v]=x,updt(1,n,1,v);//v!=n+1
      pre[x]=u;c[x]=y;s[t].insert(x);
      updt(1,n,1,x);
      if(x!=1)updt(1,n,1,x-1);//x!=1//为了改差分 
    }
      else
    {
      int L,R,k;
      scanf("%d%d%d",&L,&R,&k);L^=lt;R^=lt;k^=lt;
      if(L==R){printf("Yes
");lt++;continue;}//放在下面那个if的上面! 
      Node ans0=query(1,n,1,L,R-1),ans=ans0+query(1,n,1,R,R);//为了差分弄ans0 
      if(!k)    //放在下面那个if的上面! 
        {
          if(ans.mx==ans.mn)printf("Yes
"),lt++;
          else printf("No
");
          continue;
        }
      if(ans.lst<L&&ans.mx-ans.mn==k*(R-L)&&ans0.g==k)printf("Yes
"),lt++;
      else printf("No
");
    }
    }
  return 0;
}
原文地址:https://www.cnblogs.com/Narh/p/9300742.html