​http://acm.hdu.edu.cn/showproblem.php?pid=5930​

先预处理出整个区间有多少个gcd 统计每个gcd出现多少次

然后还有一个巧妙的地方就是 对每个把tar位置的数改为val的修改 把[1,tar]和[tar,n]这左右边各有多少gcd值不同的以tar为右左端点的区间找出并记下来 因为这些区间数量很少 所以用两层for循环处理 对于一个gcd的出现次数 如果加之前为零 总答案加加 如果减之后为零 总答案减减

和hdu5726类似 具体细节详见之前写的博客​

#include <cstdio>
#include <vector>
#include <cstring>
#include <algorithm>
using namespace std;
#define ll long long

struct node1
{
int l;
int r;
int val;
};

struct node2
{
int gcd;
ll len;
};

node1 tree[200010];
ll cnt[1000010];
int num[50010];
int n,q,ans;

int getgcd(int a,int b)
{
int t;
while(b>0)
{
t=b;
b=a%b;
a=t;
}
return a;
}

void pushup(int cur)
{
tree[cur].val=getgcd(tree[2*cur].val,tree[2*cur+1].val);
}

void build(int l,int r,int cur)
{
int m;
tree[cur].l=l;
tree[cur].r=r;
if(l==r)
{
tree[cur].val=num[l];
return;
}
m=(l+r)/2;
build(l,m,2*cur);
build(m+1,r,2*cur+1);
pushup(cur);
}

int queryI(int tp,int pl,int pr,int gcd,int cur)
{
int res;
if(pl<=tree[cur].l&&tree[cur].r<=pr&&tree[cur].val%gcd==0) return 0;
if(tree[cur].l==tree[cur].r) return tree[cur].l;
res=0;
if(!tp)
{
if(pr>=tree[2*cur+1].l) res=queryI(tp,pl,pr,gcd,2*cur+1);
if(res==0&&pl<=tree[2*cur].r) res=queryI(tp,pl,pr,gcd,2*cur);
}
else
{
if(pl<=tree[2*cur].r) res=queryI(tp,pl,pr,gcd,2*cur);
if(res==0&&pr>=tree[2*cur+1].l) res=queryI(tp,pl,pr,gcd,2*cur+1);
}
return res;
}

int queryII(int pl,int pr,int cur)
{
int res;
if(pl<=tree[cur].l&&tree[cur].r<=pr)
{
return tree[cur].val;
}
res=0;
if(pl<=tree[2*cur].r) res=getgcd(queryII(pl,pr,2*cur),res);
if(pr>=tree[2*cur+1].l) res=getgcd(queryII(pl,pr,2*cur+1),res);
return res;
}

void update(int tar,int val,int cur)
{
if(tree[cur].l==tree[cur].r)
{
tree[cur].val=val;
return;
}
if(tar<=tree[2*cur].r) update(tar,val,2*cur);
else update(tar,val,2*cur+1);
pushup(cur);
}

void init()
{
int i,p,res,gcd;
memset(cnt,0,sizeof(cnt));
ans=0;
for(i=1;i<=n;i++)
{
p=i,gcd=num[p];
while(p<=n)
{
res=queryI(1,p,n,gcd,1);
if(res==0) res=n+1;
if(cnt[gcd]==0) ans++;
cnt[gcd]+=(res-p);
gcd=getgcd(gcd,num[res]);
p=res;
}
}
}

void solve(int tar,int val)
{
vector <node2> prel,prer;
node2 tmp;
ll len;
int p,l,r,m,i,j,res,gcd;
p=tar,gcd=num[tar];
while(p>=1)
{
res=queryI(0,1,p,gcd,1);
tmp.gcd=gcd,tmp.len=p-res;
prel.push_back(tmp);
gcd=getgcd(gcd,num[res]);
p=res;
}
p=tar,gcd=num[tar];
while(p<=n)
{
res=queryI(1,p,n,gcd,1);
if(res==0) res=n+1;
tmp.gcd=gcd,tmp.len=res-p;
prer.push_back(tmp);
gcd=getgcd(gcd,num[res]);
p=res;
}

for(i=0;i<prel.size();i++)
{
for(j=0;j<prer.size();j++)
{
len=prel[i].len*prer[j].len;
gcd=getgcd(prel[i].gcd,prer[j].gcd);
if(cnt[gcd]==0) ans++;
cnt[gcd]+=len*val;
if(cnt[gcd]==0) ans--;
}
}
}

int main()
{
int t,cas,i,tar,val;
scanf("%d",&t);
for(cas=1;cas<=t;cas++)
{
scanf("%d%d",&n,&q);
for(i=1;i<=n;i++)
{
scanf("%d",&num[i]);
}
build(1,n,1);
init();
printf("Case #%d:\n",cas);
while(q--)
{
scanf("%d%d",&tar,&val);
solve(tar,-1);
update(tar,val,1);
num[tar]=val;
solve(tar,1);
printf("%d\n",ans);
}
}
return 0;
}