一、题目
二、解法
对于这种维护奇怪东西的题就可以考虑分块 q w q qwq qwq。
看上去 gcd \gcd gcd和异或没有什么联系,也不好一起维护,所以我们分开维护,本题的复杂度是由于一个数组中前缀 gcd \gcd gcd的取值最多 log \log log种,因为改变一次至少要减 1 2 \frac{1}{2} 21
那么每一个块我们维护这些值:块内 gcd \gcd gcd;前缀 x o r xor xor (整个数组);单个元素值; x o r xor xor修改标记。为了方便查询,我们先把所有的前缀 x o r xor xor塞进 s e t set set中,修改就十分暴力了,先暴力重构当前块内的 gcd \gcd gcd和 x o r xor xor,然后后面的块直接打 x o r xor xor修改标记就行了(相当于懒标记)。
查询的话维护一个前缀 gcd \gcd gcd,如果经过这个块 gcd \gcd gcd不会改变的话,就说明块内 gcd \gcd gcd前缀和是一样的,直接在 s e t set set中查询即可。否则说明块内改变了前缀 gcd \gcd gcd,直接暴力访问块内每一个位置(不会超过 log \log log次)。
总时间复杂度 O ( n n log n ) O(n\sqrt n\log n) O(nnlogn),这道题不怎么卡常,贴个代码 q w q qwq qwq,顺便说一句,注意异或和等号优先级的问题,异或的优先级不比等号高(所以必须打括号)
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <set>
using namespace std;
const int M = 100005;
#define ll long long
#define mp make_pair
#define int long long
int read()
{
int x=0,flag=1;
char c;
while((c=getchar())<'0' || c>'9') if(c=='-') flag=-1;
while(c>='0' && c<='9') x=(x<<3)+(x<<1)+(c^48),c=getchar();
return x*flag;
}
int n,m,k,nn,a[M],xp[M],g,ans;ll p;
char str[10];
int bel(int n)
{
return (n-1)/nn+1;
}
int gcd(int a,int b)
{
return !b?a:gcd(b,a%b);
}
struct block
{
int val[320],L,R,len,Gcd,x[320],tag;
set<pair<int,int> >s;
void reset()
{
Gcd=val[1];
for(int i=2;i<=len;i++) Gcd=gcd(Gcd,val[i]);
}
void build(int l,int r)
{
L=l;R=r;len=r-l+1;
for(int i=l;i<=r;i++)
{
val[i-l+1]=a[i];
x[i-l+1]=xp[i];
s.insert(mp(xp[i],i-l+1));
}
reset();
}
void modify(int pos,int dlt)
{
pos=pos-L+1;
for(int i=pos;i<=len;i++)
{
s.erase(mp(x[i],i));
x[i]^=dlt;
s.insert(mp(x[i],i));
}
val[pos]^=dlt;
reset();
}
void get()
{
for(int i=1;i<=len;i++)
{
g=gcd(g,val[i]);
if((ll)g*(x[i]^tag)==p)
{
ans=i+L-1;
return ;
}
}
}
void Find()
{
if(p%g) return ;
set<pair<int,int> >::iterator it;
it=s.lower_bound(mp((p/g)^tag,0));
if(it==s.end() || (it->first^tag)!=(p/g)) return ;
//异或的优先级竟然没有等号高[\doge]!!
ans=it->second+L-1;
}
}b[320];
signed main()
{
n=read();nn=sqrt(n);
for(int i=1;i<=n;i++)
a[i]=read(),xp[i]=xp[i-1]^a[i];
m=read();k=bel(n);
for(int i=1;i<k;i++) b[i].build((i-1)*nn+1,i*nn);
b[k].build((k-1)*nn+1,n);
while(m--)
{
scanf("%s",str);
if(str[0]=='M')
{
int pos=read()+1,x=read();
int dlt=a[pos]^x;a[pos]=x;
for(int i=bel(pos)+1;i<=k;i++) b[i].tag^=dlt;
b[bel(pos)].modify(pos,dlt);
}
else
{
scanf("%lld",&p);
g=0;ans=-1;
for(int i=1;i<=k && ans==-1;i++)
{
if(g==gcd(g,b[i].Gcd))
b[i].Find();
else
b[i].get();
}
if(ans==-1) puts("no");
else printf("%lld\n",ans-1);
}
}
}