背景:
剩下的博客有空再补。
题目传送门:
https://www.luogu.org/problem/P4108
题意:
一个序列,两种操作。
[
1
]
.
[1].
[1].将第
x
x
x位置的值改为
y
y
y;
[
2
]
.
[2].
[2].询问
gcd
(
a
1
,
a
2
,
a
3
.
.
.
,
a
p
)
∗
xor
(
a
1
,
a
2
,
a
3
,
.
.
.
,
a
p
)
=
x
\gcd(a_1,a_2,a_3...,a_p)*\text{xor}(a_1,a_2,a_3,...,a_p)=x
gcd(a1,a2,a3...,ap)∗xor(a1,a2,a3,...,ap)=x的最小的位置
p
p
p。
思路:
之前提到过,前缀
gcd
\gcd
gcd的个数是
log
值
域
\log值域
log值域级别的。
那么考虑分块。
维护当前这一块的前缀
gcd,xor
\text{gcd,xor}
gcd,xor(当前这一块的前缀),以及用个
map
\text{map}
map维护前缀
xor
\text{xor}
xor出现在当前这一块中的位置。
修改直接暴力将块内的信息全都修改掉。
考虑询问,前缀
gcd
\gcd
gcd的个数是
log
值
域
\log值域
log值域级别的,不妨考虑查看当前这一块末尾的前缀
gcd
\text{gcd}
gcd(整个序列的前缀)是否等于上一块的前缀
gcd
\text{gcd}
gcd(整个序列的前缀)。
若等于,我们在当前这一块的
map
\text{map}
map查看序列中是否存在
x
G
C
D
\frac{x}{GCD}
GCDx(
GCD
\text{GCD}
GCD为这个前缀
gcd
\gcd
gcd)存在则在
map
\text{map}
map找到那个最小的位置。
反之,直接进去暴力寻找,因为前缀
gcd
\text{gcd}
gcd的个数可以保证。
理论时间复杂度:
Θ
(
n
log
2
值
域
)
\Theta(n\log^2值域)
Θ(nlog2值域),实际约为:
Θ
(
n
log
值
域
)
\Theta(n\log值域)
Θ(nlog值域)。
注意
long long
\text{long long}
long long的问题。
代码:
实际块的大小为 n 0.55 n^{0.55} n0.55比较快,可以卡过。
#pragma GCC optimize("Ofast")
#include<cstdio>
#include<cstring>
#include<map>
#include<cmath>
#include<algorithm>
#define LL long long
#define R register
#define I inline
using namespace std;
int n,m,Sqrt,cnt=0;
int d[100010],belong[100010];
struct node{int l,r;int h[1510],g[1510];map<int,int> MAP;} a[1510];//h:异或,g:gcd
int gcd(int x,int y)
{
return !y?x:gcd(y,x%y);
}
I void work(int x)
{
int op=0,t=1;
a[x].MAP.clear();
a[x].g[1]=a[x].h[1]=d[a[x].l],a[x].MAP[d[a[x].l]]=a[x].l;
for(R int i=a[x].l+1;i<=a[x].r;i++)
{
t++;
a[x].g[t]=gcd(a[x].g[t-1],d[i]);
a[x].h[t]=(a[x].h[t-1]^d[i]);
if(!a[x].MAP[a[x].h[t]]) a[x].MAP[a[x].h[t]]=i;
}
}
I void init()
{
//Sqrt=sqrt(n);
Sqrt=pow(n,0.55);
int last=-1,now;
for(R int i=1;i<=n;i++)
{
now=i/Sqrt+1;
belong[i]=now;
if(now!=last) a[cnt].r=i-1,a[++cnt].l=i;
last=now;
}
a[cnt].r=n;
for(R int i=1;i<=cnt;i++)
work(i);
}
I int solve(LL x)
{
int tmp1=a[1].g[1],tmp2=0;
if((LL)a[1].g[1]*a[1].h[1]==x) return 1;
for(R int i=1;i<=cnt;i++)
{
int limit=a[i].r-a[i].l+1;
if(tmp1!=gcd(tmp1,a[i].g[limit]))
{
for(R int j=1;j<=limit;j++)
{
int yy=gcd(tmp1,a[i].g[j]);
if(!(x%yy))
{
int op=a[i].MAP[(x/yy)^tmp2];
if(op) return op;
}
}
}
else if(!(x%tmp1))
{
int op=a[i].MAP[(x/tmp1)^tmp2];
if(op) return op;
}
tmp1=gcd(tmp1,a[i].g[limit]),tmp2^=a[i].h[limit];
}
return -1;
}
I char getc()
{
static char buf[1<<20],*fs,*ft;
return(fs==ft&&(ft=(fs=buf)+fread(buf,1,1<<20,stdin)),fs==ft)?EOF:*fs++;
}
I void readll(LL &x)
{
char ch=getc(),f=1;
for(x=0;ch=='\n'||ch==' ';ch=getc());
for(;ch!='\n'&&ch!=' ';ch=getc())
x=((x+(x<<2))<<1)+(ch^0x30);
}
I void read(int &x)
{
char ch=getc(),f=1;
for(x=0;ch=='\n'||ch==' ';ch=getc());
for(;ch!='\n'&&ch!=' ';ch=getc())
x=((x+(x<<2))<<1)+(ch^0x30);
}
I void read_str(char *str)
{
char ch=getc();
for(;ch=='\n'||ch==' ';ch=getc());
for(;ch!='\n'&&ch!=' ';ch=getc())
*str=ch,str++;
*str='\0';
}
char s[10];
int main()
{
int x,y;
LL z;
read(n);
for(R int i=1;i<=n;i++)
read(d[i]);
init();
read(m);
for(R int i=1;i<=m;i++)
{
read_str(s+1);
if(s[1]=='M')
{
read(x),read(y);
x++;
d[x]=y;
work(belong[x]);
}
else
{
readll(z);
int tmp=solve(z);
if(tmp==-1) printf("no\n"); else printf("%d\n",tmp-1);
}
}
}