[BZOJ4028] [HEOI2015] 公约数数列 - 分块

大分块是nsqrt(n)logn的qwq

#include"bits/stdc++.h"
#define mmap map<int,int>::iterator
#define mpar make_pair
#define fge getchar()
using namespace std;
typedef long long ll;
template<class MyInt>void read(MyInt&x){
    x=0;char ch=fge;int f=1;
    while(ch>'9'||ch<'0'){if(ch=='-')f=-1;ch=fge;}
    while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=fge;
    x*=f;
}
 
const int N=100005,S=505,Q=10005;
int size,n,val[N],gcdsum[N],xorsum[N],q;
char opt[23];ll p;
map<int,int>data[S];
 
int gcd(int x,int y){
    if(!x||!y)return x*(!!x)+y*(!!y); 
    return gcd(y,x%y);
}
 
inline void edit(int x,int tmp){
    int b=x/size;mmap i=data[b].find(xorsum[x]);
    if(i!=data[b].end())data[b].erase(xorsum[x]);
    xorsum[x]=tmp;data[b].insert(mpar(xorsum[x],x));
}
 
inline void change(int x,int tmp){
    int w = x/size; val[x]=tmp;
    if(x==w*size) gcdsum[x]=tmp,edit(x,tmp);
    else gcdsum[x]=gcd(tmp,gcdsum[x-1]),edit(x,xorsum[x-1]^tmp);
    for (register int i=x+1; i<min((w+1)*size,n); i++)
        gcdsum[i]=gcd(gcdsum[i-1],val[i]),edit(i,xorsum[i-1]^val[i]);
}
 
inline int qry(ll p){
    int g=gcdsum[0],last=0;
    for(register int i=0;i<n;i+=size){
        if(gcdsum[min(i+size,n)-1]%g==0){
            if(p%g==0){
                if(p/g>1<<30) continue;
                mmap h=data[i/size].find((p/g)^last);
                if(h!=data[i/size].end()) return h->second;
            }
        }
        else for(register int j=i;j<min(i+size,n);j++){
            if(gcdsum[j]%g)g=gcd(gcdsum[j],g);
            if(p%g==0&&(p/g)==(xorsum[j]^last))return j;
        }
        last=last^xorsum[i+size-1];
    }
    return -1;
}
int main(){
    read(n);int i,j,x,y;size=(int)sqrt(n*5.0);
    for(i=0;i<n;i++)read(val[i]);
    for(i=0;i<n;i+=size){
        gcdsum[i]=xorsum[i]=val[i];
        data[i/size].insert(mpar(val[i],i)); 
        for(j=i+1;j<min(i+size,n);j++){
            gcdsum[j]=gcd(gcdsum[j-1],val[j]);
            xorsum[j]=xorsum[j-1]^val[j];
            data[i/size].insert(mpar(xorsum[j],j));
        }
    }
    read(q);
    for(i=1;i<=q;i++){
        scanf("%s",opt);
        if(opt[0]=='M'){
            scanf("%d%d\n",&x,&y);
            change(x,y);
        } else{
            scanf("%lld\n",&p);int ans=qry(p);
            if(ans==-1)puts("no");else printf("%d\n",ans); 
        }
    }
    return 0; 
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值