【题解】[HEOI2015] 公约数数列
sol:
 利用分块思想,尽量利用整块的信息查询。
首先只考虑查询。从左往右遍历每个整块,如果  
     
      
       
       
         gcd 
        
       
          
        
       
         ( 
        
       
         t 
        
       
         m 
        
       
         p 
        
       
         , 
        
       
         t 
        
       
         [ 
        
       
         i 
        
       
         ] 
        
       
         . 
        
       
         gcd 
        
       
          
        
       
         ) 
        
       
         < 
        
       
         t 
        
       
         m 
        
       
         p 
        
       
      
        \gcd(tmp,t[i].\gcd)<tmp 
       
      
    gcd(tmp,t[i].gcd)<tmp 就暴力遍历块内所有元素,否则直接整块查询(用 std::map 暴力即可)。
每次修改就暴力重构块。
我们来分析时间复杂度为什么是对的。根据 gcd  \gcd gcd 性质不难得出每次 t m p tmp tmp 至少退化成原来的一般,所以暴力遍历的块的个数不超过 log  a 0 \log{a_0} loga0 次。时间复杂度为 O ( q n ( log  n + log  a ) ) O(q\sqrt{n}(\log{\sqrt{n}+\log a)}) O(qn(logn+loga)) 。这个 log  \log log 实际远小于预期。
总结:本题主要是考虑从询问入手,将 遍历到的 / 重构的 次数尽量控制得小。
#include<bits/stdc++.h>
#define db double 
#define ll long long
#define mkp make_pair
#define pii pair<int,int> 
#define inf 0x3f3f3f3f
#define fi first
#define se second
using namespace std;
const int Maxn=1e5+5;
const int Maxm=320;
const int mod=23333333;
//如果加上这个块后 gcd 变小了,我们就直接暴力扫整个块
//否则直接在块里面查有没有 xor 为 ? 的数 
//每次查询暴力扫到的块不超过 log 个(啊啊啊) 
inline ll read() {
	ll x=0,f=1; char c=getchar();
	while(c<'0'||c>'9') {
		c=getchar();
	}
	while(c>='0'&&c<='9') {
		x=(x<<1)+(x<<3)+c-'0';
		c=getchar();
	}
	return x;
}
int n,m,block,L[Maxn],R[Maxn],bl[Maxn],a[Maxn];
map<ll,int> tong[Maxm];
char op[10];
struct node{
	ll gcd,xo;
}t[Maxm];
ll gcd(ll x,ll y) {
	return y==0?x:gcd(y,x%y);
} 
void build(int id) {
	tong[id].clear();
	t[id].gcd=t[id].xo=0;
	for(int i=L[id];i<=R[id];i++) {
		t[id].gcd=gcd(t[id].gcd,a[i]);
		t[id].xo^=a[i];
		if(tong[id].find(t[id].xo)==tong[id].end())tong[id][t[id].xo]=i;
	}
}
void solve(ll mid) {
	ll tmp1=0,tmp2=0;
	for(int i=1;i<=(n-1)/block+1;i++) {
		if(gcd(tmp1,t[i].gcd)!=tmp1) {
			for(int j=L[i];j<=R[i];j++) {
				tmp1=gcd(tmp1,a[j]);
				tmp2^=a[j];
				if(tmp1*tmp2==mid) {
					printf("%d\n",j-1);
					return;
				}
			}
		}
		else {
			//tmp1 * (tmp2 ^ x) = mid
			if(mid%tmp1) {
				tmp2^=t[i].xo;
				continue;
			}
			if(tong[i].find((mid/tmp1)^tmp2)!=tong[i].end()) {
				printf("%d\n",tong[i][(mid/tmp1)^tmp2]-1);
				return;
			}
			tmp2^=t[i].xo;
		}
	}
	printf("no\n");
	return;
}
signed main() {
//	freopen("data.in","r",stdin);
	n=read();block=sqrt(n);
	for(int i=1;i<=n;i++) {
		a[i]=read();
		bl[i]=(i-1)/block+1;
	}
	for(int i=1;i<=(n-1)/block+1;i++) {
		L[i]=(i-1)*block+1;
		R[i]=min(n,i*block);
		build(i);
	}
	m=read();
	for(int i=1;i<=m;i++) {
		scanf("%s",op);
		if(op[0]=='M') {
			int x=read(),y=read();
			x++;
		    a[x]=y;
		    build(bl[x]);
		}
		else {
			ll x=read();
			solve(x);
		}
	}
}

 
                
            
         
         浙公网安备 33010602011771号
浙公网安备 33010602011771号