Luogu P4108 [HEOI2015]公约数数列
Luogu P4108(分块)
观察题目要求,修改操作为单点修改,而查询为前缀查询,再注意到 (还有看标签) ,知道这道题可以用分块进行解决。
首先是关于修改,题目要求单点修改,将区间分块后,单点修改可以在块内暴力修改,时间复杂度
然后就是如何查询的问题。对于
我们维护好每个块中的前缀
修改操作也很简单,获取当前下标所在块编号,然后直接在当前块中扫一遍,暴力维护前缀
#include<cstdio>
#include<unordered_map>
#include<cmath>
#include<algorithm>
#include<cstdlib>
#define LL long long
#define mem(a,b) memset(a,b,sizeof(a));
#define map unordered_map
using namespace std;
template<typename T> inline void read(T &k)
{
k=0;
T flag=1;char b=getchar();
while (b<'0' || b>'9') {flag=(b=='-')?-1:1;b=getchar();}
while (b>='0' && b<='9') {k=(k<<3)+(k<<1)+(b^48);b=getchar();}
k*=flag;
}
const int _SIZE=1e5;
int n,q;
int a[_SIZE+5];
map<int,int> XORPos[_SIZE+5];//记录XOR值在每个块中出现的位置,这里的map被定义为了unordered_map
int L[_SIZE+5],R[_SIZE+5];//每个块的左右断点
int len,cnt,pos[_SIZE+5];//块长,块个数,每个点所在块编号
int XOR[_SIZE+5],GCD[_SIZE+5];//前缀XOR值,前缀GCD
inline int gcd(int x,int y) {return __gcd(x,y);}//计算gcd
void PreWork()//预处理
{
len=sqrt(n);//块长为n^(1/2)
cnt=(n-1)/len+1;//块的个数
for (int i=1;i<=cnt;i++)//处理每一个块
{
L[i]=(i-1)*len+1;//左端点
R[i]=min(i*len,n);//右端点
pos[L[i]]=i;//将块的左端点特别赋值,因为它是当前块的开头
GCD[L[i]]=a[L[i]];
XOR[L[i]]=a[L[i]];
if (XORPos[i].find(XOR[L[i]])==XORPos[i].end())//记得将开头的值放入map中
XORPos[i][XOR[L[i]]]=L[i];
for (int j=L[i]+1;j<=R[i];j++)//遍历当前块
{
pos[j]=i;//对应块编号
GCD[j]=gcd(GCD[j-1],a[j]);//前缀GCD
XOR[j]=XOR[j-1]^a[j];//前缀XOR和
if (XORPos[i].find(XOR[j])==XORPos[i].end())//插入map
XORPos[i][XOR[j]]=j;
}
}
}
void update(int x,int v)//更新,将位置x更新为v
{
a[x]=v;//更改值
int which=pos[x];//获取块编号
GCD[L[which]]=a[L[which]];//以下与预处理方式相同
XOR[L[which]]=a[L[which]];
XORPos[which].clear();
if (XORPos[which].find(XOR[L[which]])==XORPos[which].end())
XORPos[which][XOR[L[which]]]=L[which];
for (int j=L[which]+1;j<=R[which];j++)
{
GCD[j]=gcd(GCD[j-1],a[j]);
XOR[j]=XOR[j-1]^a[j];
if (XORPos[which].find(XOR[j])==XORPos[which].end())
XORPos[which][XOR[j]]=j;
}
}
int query(LL x)//查询值x对应的答案p
{
int gcdtemp=a[1],temp=0;//记录1~j的前缀GCD与前缀XOR和
for (int i=1;i<=cnt;i++)//以块为单位
{
if (gcd(gcdtemp,GCD[R[i]])==gcdtemp)//如果当前块的GCD全部相同
{
if (x%(gcdtemp)==0 && XORPos[i].find(x/gcdtemp^temp)!=XORPos[i].end())
return XORPos[i][x/gcdtemp^temp];//查询有没有符合答案的XOR值,有就返回
else
{
temp^=XOR[R[i]];//将块的XOR和全部加在temp上
gcdtemp=gcd(gcdtemp,GCD[R[i]]);//更新GCD
continue;//该块处理完成
}
}
for (int j=L[i];j<=R[i];j++)//如果GCD值不相等
{
gcdtemp=gcd(gcdtemp,a[j]);
temp^=a[j];//更新1~j的gcdtemp与temp
if ((LL)gcdtemp*temp==x) return j;//如果符合答案要求即返回,记得long long
}
}
return -1;//找完所有块也没有答案,返回一个-1
}
int main()
{
read(n);
for (int i=1;i<=n;i++) read(a[i]);
PreWork();
read(q);
char com[25];
int pos,ans;LL val;
for (int i=1;i<=q;i++)
{
scanf("%s",com);
if (com[0]=='M')//修改
{
read(pos);read(val);
pos++;
update(pos,val);
}
else//查询
{
read(val);
ans=query(val);
if (ans!=-1) printf("%d\n",ans-1);
else puts("no");//返回值为-1,即没有答案
}
}
return 0;
}
分类:
标签:
,
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步