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