版权声明:随意转载,愿意的话提一句作者就好了 https://blog.csdn.net/stone41123/article/details/84134199
Link
Diffculty
算法难度5,思维难度7,代码难度6
Description
给定长度为 的序列,要求支持两种操作,共 个:
- 给定 ,将 位置的值修改成
- 给定 ,求最小正整数 使得
Solution
神仙题,不会不会。
有个性质,就是前缀 一定是单调不升的,这个很重要,我们可以在这个基础上分块。
我们对序列分块之后,记 为从块头到 的前缀 , 为从块头到 的前缀 。
修改就暴力重构这个块。
查询我们一个块一个块处理,我们考虑之前所有块的前缀 和加上这个块的前缀 是否相等。
我们记前面所有块的 为 ,所有块的 为
如果相等,那么我们可以直接在块内找是否存在一个
这个东西可以预处理和修改的时候每个块都维护一个 ,就能快速查询了。
扫描二维码关注公众号,回复:
4094437 查看本文章
如果不相等,那么暴力枚举块内每个位置,直接判断。
这样子复杂度就是 了,因为每次变化 至少减少一半,所以不相等的最多 次。
代码注意一下细节就好了。
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<iostream>
#include<algorithm>
#include<map>
#define LL long long
using namespace std;
inline int read(){
int x=0,f=1;char ch=' ';
while(ch<'0' || ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0' && ch<='9')x=x*10+(ch^48),ch=getchar();
return f==1?x:-x;
}
inline LL readLL(){
LL x=0;int f=1;char ch=' ';
while(ch<'0' || ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0' && ch<='9')x=x*10LL+(ch^48),ch=getchar();
return f==1?x:-x;
}
const int N=1e5+5,sqN=320;
map<LL,int> mp[sqN];
int n,a[N],q,block,cnt,belong[N],L[N],R[N],f1[N],f2[N];
inline LL gcd(LL a,LL b){return !b?a:gcd(b,a%b);}
int main(){
n=read();
for(int i=1;i<=n;++i)a[i]=read();
block=sqrt(n);
cnt=n/block;
if(n%block)cnt++;
for(int i=1;i<=n;++i)belong[i]=(i-1)/block+1;
for(int i=1;i<=cnt;++i)L[i]=(i-1)*block+1,R[i]=i*block;
R[cnt]=n;
for(int i=1;i<=cnt;++i){
f1[L[i]]=a[L[i]];
f2[L[i]]=a[L[i]];
mp[i][f2[L[i]]]=L[i];
for(int j=L[i]+1;j<=R[i];++j){
f1[j]=gcd(f1[j-1],a[j]);
f2[j]=f2[j-1]^a[j];
if(!mp[i][f2[j]])mp[i][f2[j]]=j;
}
}
q=read();
for(int s=1;s<=q;++s){
char ch[10];
scanf("%s",ch+1);
if(ch[1]=='M'){
int x=read()+1,v=read();
a[x]=v;
int i=belong[x];
mp[i].clear();
f1[L[i]]=a[L[i]];
f2[L[i]]=a[L[i]];
mp[i][f2[L[i]]]=L[i];
for(int j=L[i]+1;j<=R[i];++j){
f1[j]=gcd(f1[j-1],a[j]);
f2[j]=f2[j-1]^a[j];
if(!mp[i][f2[j]])mp[i][f2[j]]=j;
}
}
else{
LL x=readLL();int flag=0;
LL lastgcd,lastxor;
for(int i=1;i<=R[1];++i){
if((LL)f1[i]*f2[i]==x){
flag=1;
printf("%d\n",i-1);
break;
}
}
if(flag)continue;
lastgcd=f1[R[1]];
lastxor=f2[R[1]];
for(int i=2;i<=cnt;++i){
int nowgcd=gcd(lastgcd,f1[R[i]]);
if(nowgcd==lastgcd){
if(x%nowgcd){
lastxor^=f2[R[i]];
continue;
}
int num=mp[i][(LL)(x/nowgcd)^lastxor];
if(num){
flag=1;
printf("%d\n",num-1);
break;
}
lastxor^=f2[R[i]];
}
else{
for(int j=L[i];j<=R[i];++j){
lastgcd=gcd(lastgcd,a[j]);
lastxor^=a[j];
if(lastgcd*lastxor==x){
flag=1;
printf("%d\n",j-1);
break;
}
}
if(flag)break;
}
}
if(flag)continue;
else printf("no\n");
}
}
return 0;
}