看着这么神的题,最后发现是个“聪明人”打的暴力。。
首先进行分块,维护每一块内的
Gcd和Xor
,每个块内存下二元组
x,Xor
表示位置和当前位置的亦或值,按照亦或值为第一关键字排序。
对于一次修改就将块内信息重新维护,每次
O(n√logn√)
对于一次询问,记
LastGcd,LastXor
分别表示之前的
Gcd和Xor
每个块依次查询,如果
gcd(LastGcd,Gcdi)==LastGcd
。也就表明取到当前块的任意一个位置,总的
gcd
都是
LastGcd
。那么就是在块中查找是否存在一个
Xor
值为
x/LastGcd
。这个在排序好的数组中二分就可以了。复杂度是
O(logn√)
。
其它情况下就暴力查询。每次
O(n√)
为什么这样做复杂度有保障呢!!?
如果
gcd(LastGcd,Gcdi)!=LastGcd
。那么
LastGcd
就会至少缩小两倍。
那么暴力查询最多只会做
O(logmax(ai))
,然后
ai<=109
。所以一次
Query
最多只会做30次暴力查询。
复杂度大概是
O(N(N−−√+logN)+QN−−√logN)
【代码】
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cmath>
#define N 100005
using namespace std;
typedef long long ll;
typedef pair<ll,int> pa;
ll read()
{
ll x=0,f=1;char ch=getchar();
while(!isdigit(ch)){if(ch=='-') f=-1;ch=getchar();}
while(isdigit(ch)){x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
return x*f;
}
int n,m,block,tot;
int bl[N],Num[320],L[320],R[320];
ll a[N],Xor[320],Gcd[320];
bool Flag[320];
class Hash{
public:
int id;ll x;
}hash[N];
bool operator <(Hash A,Hash B) {
return A.x<B.x||(A.x==B.x&&A.id<B.id);
}
ll _Gcd(ll a,ll b){
return b==0?a:_Gcd(b,a%b);
}
void Rebuild(int x)
{
Gcd[x]=a[L[x]];Xor[x]=Flag[x]=0;
for(register int i=L[x];i<=R[x];i++) {
Gcd[x]=_Gcd(Gcd[x],a[i]);
Xor[x]^=a[i];hash[i].x=Xor[x],hash[i].id=i;
}
sort(hash+L[x],hash+R[x]+1);
}
void Input_Init()
{
n=read();block=sqrt(n);
for(register int i=1;i<=n;i++) {
a[i]=read();bl[i]=(i-1)/block+1;
if(bl[i]!=bl[i-1]) L[bl[i]]=i;
if(i%block==0||i==n) R[bl[i]]=i;
}
tot=bl[n];
for(register int i=1;i<=tot;i++) Rebuild(i);
}
void Modify()
{
int x;ll y;
x=read()+1,y=read();a[x]=y;Flag[bl[x]]=1;
}
int Find(int L,int R,ll y)
{
int rtn=0;
while(L<=R)
{
int mid=L+R>>1;
if(hash[mid].x>=y) rtn=mid,R=mid-1;
else L=mid+1;
}
if(hash[rtn].x!=y) return 0;
return hash[rtn].id;
}
int Brute_Force(int x,ll LastGcd,ll LastXor,ll y)
{
for(register int i=L[x];i<=R[x];i++)
{
LastGcd=_Gcd(LastGcd,a[i]);
LastXor^=a[i];
if(LastGcd*LastXor==y) return i;
}
return 0;
}
int Query()
{
ll LastXor=0,LastGcd=a[1],x=read();
for(register int i=1;i<=tot;i++)
{
if(Flag[i]) Rebuild(i);
LastGcd=__gcd(LastGcd,Gcd[i-1]);
LastXor^=Xor[i-1];
if(_Gcd(LastGcd,Gcd[i])==LastGcd) {
if(x%LastGcd!=0) continue;
int t=Find(L[i],R[i],LastXor^x/LastGcd);
if(t) return t;
}
else {
int t=Brute_Force(i,LastGcd,LastXor,x);
if(t) return t;
}
}
return -1;
}
void Solve()
{
m=read();
while(m--)
{
char ch[10];scanf("%s",ch);
if(ch[0]=='M') Modify();
else {
int t=Query();
if(t==-1) printf("no\n");
else printf("%d\n",t-1);
}
}
}
int main()
{
Input_Init();
Solve();
return 0;
}