• 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;
    }
  • 相关阅读:
    Python 入门变量类型标识符和关键字
    对于msSql中exists操作符求值的疑惑
    那个蛋痛的list的remove_if中用到的对像函数
    继承一个虚类的时候要小心是,并使其实例化时.必须使其全实重写了纯虚的方法...类定义的位置
    MSSQL(TSQL)中的varchar不指定大小好像一般来说只有一个的长度
    关于TSQL中触发器的只言片语
    MSSQL十秒一次的job
    用了Rime输入法之后,发现IE要关闭保护模式才能输入
    三性原则,指的是商业银行的“安全性、流动性、效益性
    九选三
  • 原文地址:https://www.cnblogs.com/Narh/p/9300742.html
Copyright © 2020-2023  润新知