BZOJ4373: 算术天才⑨与等差数列

n<=3e5的数列,m<=3e5个操作:把第x个数修改成y,或询问从x到y这个区间能否构成公差z的等差数列。

二逼做法:考虑一个序列在什么情况下才能构成公差z的等差数列。

首先,最大值和最小值的差是z*(y-x)。

其次,相邻两数的差的gcd是z。

再者,没有重复的数字。

前两个比较好搞,线段树,第三个其实就是每个数Ai记一个pre[i]表示Ai之前和Ai相同的第一个数字的下标,然后区间x到y的pre的最大值<x即可。

那这个怎么修改呢,每次修改涉及到三个数字:Ai后面的某个pre[j]=i的j,修改后Ai后面某个pre[j]=i的j,Ai自己的pre。现在就是要找一定权值的大于某个数字的第一个数字,这里的数字即下标。所以每个权值开一个平衡树set存这个权值的所有下标,每次修改只需要lowerbound找一下Ai的下标i对应的迭代器,然后他的下一个和上一个也就很清楚了,分类看是不是最后一个和第一个来修改。

还有一个问题,权值被强制在线了,要写个动态离散化,二逼离散化:map,文艺离散化:hash。

  1 #include<cstdio>
  2 #include<cstring>
  3 #include<algorithm>
  4 #include<cstdlib>
  5 #include<set>
  6 //#include<time.h>
  7 #include<math.h>
  8 //#include<assert.h>
  9 //#include<queue>
 10 #include<iostream>
 11 using namespace std;
 12  
 13 int n,m;
 14 #define maxn 600011
 15 #define It set<int>::iterator
 16 int num[maxn],pre[maxn];
 17 set<int> s[maxn<<1];
 18 struct Doo
 19 {
 20     int id,x,y,z;
 21 }doo[maxn];
 22 int gcd(int a,int b) {return b?gcd(b,a%b):a;}
 23 struct SMT
 24 {
 25     struct Node
 26     {
 27         int Max,Min,gcd;
 28         int l,r;
 29         int ls,rs;
 30     }a[maxn<<1];
 31     int size;
 32     SMT() {size=0;}
 33     void up(int x)
 34     {
 35         const int &p=a[x].ls,&q=a[x].rs;
 36         a[x].Max=max(a[p].Max,a[q].Max);
 37         a[x].Min=min(a[p].Min,a[q].Min);
 38         a[x].gcd=gcd(gcd(a[p].gcd,a[q].gcd),fabs(num[a[q].l]-num[a[p].r]));
 39     }
 40     void build(int &x,int L,int R)
 41     {
 42         x=++size;
 43         a[x].l=L;a[x].r=R;
 44         if (a[x].l==a[x].r)
 45         {
 46             a[x].ls=a[x].rs=0;
 47             a[x].Max=num[L];
 48             a[x].Min=num[L];
 49             a[x].gcd=0;
 50             return;
 51         }
 52         const int mid=(L+R)>>1;
 53         build(a[x].ls,L,mid);
 54         build(a[x].rs,mid+1,R);
 55         up(x);
 56     }
 57     void build() {int x;build(x,1,n);}
 58     int ql,qr,v;
 59     void modify(int x)
 60     {
 61         if (a[x].l==a[x].r) a[x].Max=a[x].Min=v;
 62         else
 63         {
 64             const int mid=(a[x].l+a[x].r)>>1;
 65             if (ql<=mid) modify(a[x].ls);
 66             else modify(a[x].rs);
 67             up(x);
 68         }
 69     }
 70     void modify(int x,int v)
 71     {
 72         ql=x;this->v=v;
 73         modify(1);
 74     }
 75     int query(int x)
 76     {
 77         if (ql<=a[x].l && a[x].r<=qr)
 78         {
 79             if (v==1) return a[x].Max;
 80             if (v==2) return a[x].Min;
 81             if (v==3) return a[x].gcd;
 82         }
 83         const int mid=(a[x].l+a[x].r)>>1;
 84         int ans;bool flag;
 85         if (v==1) ans=-1;
 86         if (v==2) ans=0x3f3f3f3f;
 87         if (v==3) ans=0,flag=0;
 88         if (ql<=mid)
 89         {
 90             if (v==1) ans=max(ans,query(a[x].ls));
 91             if (v==2) ans=min(ans,query(a[x].ls));
 92             if (v==3) ans=query(a[x].ls),flag=1;
 93         }
 94         if (qr>mid)
 95         {
 96             if (v==1) ans=max(ans,query(a[x].rs));
 97             if (v==2) ans=min(ans,query(a[x].rs));
 98             if (v==3)
 99             {
100                 if (flag) ans=gcd(ans,gcd(query(a[x].rs),fabs(num[a[a[x].rs].l]-num[a[a[x].ls].r])));
101                 else ans=query(a[x].rs);
102             }
103         }
104         return ans;
105     }
106     int query(int L,int R,int v)
107     {
108         if (L>R) return 0;
109         ql=L;qr=R;this->v=v;
110         return query(1);
111     }
112 }t;
113 struct SMT2
114 {
115     struct Node
116     {
117         int Max;
118         int l,r;
119         int ls,rs;
120     }a[maxn<<1];
121     int size;
122     SMT2() {size=0;}
123     void up(int x)
124     {
125         const int &p=a[x].ls,&q=a[x].rs;
126         a[x].Max=max(a[p].Max,a[q].Max);
127     }
128     void build(int &x,int L,int R)
129     {
130         x=++size;
131         a[x].l=L;a[x].r=R;
132         if (a[x].l==a[x].r)
133         {
134             a[x].ls=a[x].rs=0;
135             a[x].Max=pre[L];
136             return;
137         }
138         const int mid=(L+R)>>1;
139         build(a[x].ls,L,mid);
140         build(a[x].rs,mid+1,R);
141         up(x);
142     }
143     void build() {int x;build(x,1,n);}
144     int ql,qr,v;
145     void modify(int x)
146     {
147         if (a[x].l==a[x].r) a[x].Max=v;
148         else
149         {
150             const int mid=(a[x].l+a[x].r)>>1;
151             if (ql<=mid) modify(a[x].ls);
152             else modify(a[x].rs);
153             up(x);
154         }
155     }
156     void modify(int x,int v)
157     {
158         ql=x;this->v=v;
159         modify(1);
160     }
161     int query(int x)
162     {
163         if (ql<=a[x].l && a[x].r<=qr) return a[x].Max;
164         const int mid=(a[x].l+a[x].r)>>1;
165         int ans=-1;
166         if (ql<=mid) ans=max(ans,query(a[x].ls));
167         if (qr> mid) ans=max(ans,query(a[x].rs));
168         return ans;
169     }
170     int query(int L,int R)
171     {
172         if (L>R) return 0x3f3f3f3f;
173         ql=L;qr=R;
174         return query(1);
175     }
176 }tpre;
177 int lisan[maxn<<1],li=0;
178 #define maxh 1000007
179 int first[maxh],Next[maxn<<1];
180 int getid(int x)
181 {
182     int v=x%maxh;
183     for (int i=first[v];i;i=Next[i])
184         if (lisan[i]==x) return i;
185     lisan[++li]=x;
186     Next[li]=first[v];
187     first[v]=li;
188     return li;
189 }
190 bool isdigit(char c) {return c>='0' && c<='9';}
191 int qread()
192 {
193     char c;int s=0;while (!isdigit(c=getchar()));
194     do s=s*10+c-'0'; while (isdigit(c=getchar()));return s;
195 }
196 int main()
197 {
198     scanf("%d%d",&n,&m);
199     memset(first,0,sizeof(first));
200     for (int i=1;i<=n;i++) num[i]=qread();
201     for (int i=1;i<=m;i++)
202     {
203         doo[i].id=qread();
204         if (doo[i].id==1) doo[i].x=qread(),doo[i].y=qread();
205         else doo[i].x=qread(),doo[i].y=qread(),doo[i].z=qread();
206     }
207     for (int i=1;i<=n;i++)
208     {
209         int pos=getid(num[i]);
210         if (s[pos].begin()!=s[pos].end()) {It it=s[pos].end();pre[i]=*--it;}
211         else pre[i]=0;
212         s[pos].insert(i);
213     }
214     t.build();
215     tpre.build();
216     int yes=0;
217     for (int i=1;i<=m;i++)
218         if (doo[i].id==1)
219         {
220             int x=doo[i].x^yes,y=doo[i].y^yes;
221             int p=getid(num[x]);
222             It it=s[p].lower_bound(x);
223             if (++it!=s[p].end()) tpre.modify(*it,tpre.query(x,x));it--;
224             s[p].erase(it);
225             p=getid(y);
226             s[p].insert(x);
227             it=s[p].lower_bound(x);
228             if (it!=s[p].begin()) tpre.modify(x,*--it),it++;
229             else tpre.modify(x,0);
230             if (++it!=s[p].end()) tpre.modify(*it,x);
231             num[x]=y;
232             t.modify(x,y);
233         }
234         else
235         {
236             int x=doo[i].x^yes,y=doo[i].y^yes,z=doo[i].z^yes;
237             int Max=t.query(x,y,1),Min=t.query(x,y,2);
238             if (!z)
239             {
240                 if (Max!=Min) puts("No");
241                 else puts("Yes"),yes++;
242             }
243             else if (x==y) puts("Yes"),yes++;
244             else if (Max-Min!=1ll*(y-x)*z) puts("No");
245             else if (t.query(x,y,3)!=z) puts("No");
246             else if (tpre.query(x,y)>=x) puts("No");
247             else puts("Yes"),yes++;
248         }
249     return 0;
250 }
View Code

文艺做法:我们是希望这一段和等差数列尽可能接近,而最大值和最小值就可以确定等差数列的每一项,然后?序列hash!一个hash值不能确保两序列相同,那就和,平方和,立方和,等等,一起算看一不一样即可。

代码自行yy。

posted @ 2017-10-20 08:01  Blue233333  阅读(238)  评论(0编辑  收藏  举报