题目描述:
题目分析:
分块,块内维护 前缀gcd 前缀Xor
修改暴力重构
查询时若gcd(gcd(块尾,pregcd))==pregcd,则说明本块内的所有数都不影响gcd 二分查找符合要求的Xor
否则暴力查询
题目链接:
Ac 代码:
// luogu-judger-enable-o2
#include <cstdio>
#include <iostream>
#include <cmath>
#include <algorithm>
#define il inline
#define ll long long
const int maxm=110000;
struct node{
int id;
ll pxor;
}a[maxm];
int block_len,block_num;
int n,q,lx[maxm],rx[maxm];
ll val[maxm],pos[maxm],pg[maxm],xr[maxm];
inline bool comp(node x,node y)
{
return (x.pxor==y.pxor?x.id<y.id:x.pxor<y.pxor);
}
ll gcd(ll a,ll b){return b==0?a:gcd(b,a%b);}
il void work(int i)
{
pg[lx[i]]=a[lx[i]].pxor=xr[lx[i]]=val[lx[i]];
pos[lx[i]]=i;
a[lx[i]].id=lx[i];
for(int j=lx[i]+1;j<=rx[i];j++)
{
pos[j]=i,a[j].id=j;
pg[j]=gcd(pg[j-1],val[j]);
xr[j]=xr[j-1]^val[j];
a[j].pxor=xr[j];
}
std::sort(a+lx[i],a+rx[i]+1,comp);
}
il void init()
{
block_len=std::sqrt(n);
block_num=n/block_len+((n%block_len)!=0);
for(int i=1;i<=block_num;i++)
{
lx[i]=(i-1)*block_len+1,rx[i]=std::min(i*block_len,n);
work(i);
}
}
il int BS(ll x,int l,int r)
{
int ans=l;
while(l<=r)
{
int mid=(l+r)>>1;
if(a[mid].pxor>=x) ans=mid,r=mid-1;
else l=mid+1;
}
return ans;
}
il void getans()
{
ll x;
scanf("%lld",&x);
ll g=val[1],nxr=0;
for(int i=1;i<=block_num;i++)
{
int s=lx[i],t=rx[i];
if(gcd(pg[t],g)==g)
{
if(x%g==0)
{
int ans=(x/g)^nxr;
int anspos=BS(ans,s,t);
if(a[anspos].pxor==ans)
{
printf("%d\n",a[anspos].id-1);
return;
}
}
g=gcd(g,pg[t]),nxr=nxr^xr[t];
}
else
{
for(int j=s;j<=t;j++)
{
g=gcd(g,val[j]),nxr=nxr^val[j];
if(g*nxr==x)
{
printf("%d\n",j-1);
return;
}
}
}
}
printf("no\n");
}
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++)
scanf("%lld",&val[i]);
init();
scanf("%d",&q);
for(int i=1,poi;i<=q;i++)
{
char s[10];
ll x;
scanf("%s",s);
if(s[0]=='M')
{
scanf("%d%lld",&poi,&x);
poi++;
val[poi]=x;
work(pos[poi]);
}
else getans();
}
return 0;
}