GCD
2016 CCPC东北赛区
思路: 我们可以用线段树在nlogn的时间内预处理出所有的不相同的gcd数以及他们出现的个数。因为连续区间的gcd gcd的大小下降的是非常快的,所以可以结合二分求,当然打出一个ST表也可以求出,但是不太适合这个题,这个题要求动态修改,还是线段树好一点,然后对于每一次修改,我可以二分处理出以他为结尾的gcd数以及他们的区间, 不会超过logn个,取决于上边的性质,当然也可以二分处理出以他为开头的所有的gcd数以及区间,这样的话,还是不够的,如果x出现在中间内,当然就可以两边for就处理出所有的由x产生影响的,gcd,然后删除,更新,再求一遍,加上。
代码:
#include<bits/stdc++.h>
#define lson (i<<1)
#define rson (i<<1|1)
using namespace std;
typedef long long ll;
typedef pair<int,int > pii;
const int N =50005;
const int NUM=1e6+5;
int n,q;
int a[N];
int cnt[NUM];
int ans;
vector< pii >pre[N];
vector< pii >post[N];
struct node
{
int l,r;
int val;
}tr[N<<2];
void push_up(int i)
{
tr[i].val=__gcd(tr[lson].val,tr[rson].val);
}
void build(int i,int l,int r)
{
tr[i].l=l;
tr[i].r=r;
tr[i].val=0;
if(l==r)
{
tr[i].val=a[l];
return ;
}
int mid=(l+r)>>1;
build(lson,l,mid);
build(rson,mid+1,r);
push_up(i);
}
void update(int i,int aim,int val)
{
if(tr[i].l==aim&&tr[i].r==tr[i].l)
{
tr[i].val=val;
return ;
}
int mid=(tr[i].l+tr[i].r)>>1;
if(aim<=mid) update(lson,aim,val);
else update(rson,aim,val);
push_up(i);
}
int querypre(int i,int l,int r,int now,int &gcd)
{
int L=tr[i].l;
int R=tr[i].r;
int gg=tr[i].val;
if(l<=L&&r>=R)
{
if(__gcd(gcd,gg)<now)
{
if(L==R) return L;
else
{
int mid=(L+R)>>1;
int ls=0,rs=0;
rs=querypre(rson,l,r,now,gcd);
if(rs) return rs;
ls=querypre(lson,l,r,now,gcd);
return ls;
}
}
else
{
gcd=__gcd(gcd,gg);
return 0;
}
}
int mid=(L+R)>>1;
int ls=0,rs=0;
if(r>mid)rs=querypre(rson,l,r,now,gcd);
if(rs) return rs;
if(l<=mid)ls=querypre(lson,l,r,now,gcd);
return ls;
}
int querypost(int i,int l,int r,int now,int &gcd)
{
int L=tr[i].l;
int R=tr[i].r;
int gg=tr[i].val;
if(l<=L&&r>=R)
{
if(__gcd(gg,gcd)<now)
{
if(L==R) return L;
else
{
int mid=(L+R)>>1;
int ls=0,rs=0;
ls=querypost(lson,l,r,now,gcd);
if(ls) return ls;
rs=querypost(rson,l,r,now,gcd);
return rs;
}
}
else
{
gcd=__gcd(gcd,gg);
return 0;
}
}
int mid=(L+R)>>1;
int ls=0,rs=0;
if(l<=mid) ls=querypost(lson,l,r,now,gcd);
if(ls) return ls;
if(r>mid) rs=querypost(rson,l,r,now,gcd);
return rs;
}
vector< pii >ppre;
vector< pii >ppost;
void solve(int id,int op)
{
ppre.clear();
ppost.clear();
if(op==0)
{
//cout<<"lalal"<<endl;
int now=a[id];
int p=id;
while(p>=1)
{
int gcd=a[id];
int pos=querypre(1,1,id,now,gcd);
int len=p-pos;
ppre.push_back(pii(now,len));
p=pos;
if(p>=1) now=__gcd(now,a[p]);
}
//cout<<"eeee "<<endl;
now=a[id];
p=id;
while(p<=n)
{
int gcd=a[id];
//cout<<"yyyyyyyyyyyy"<<endl;
int pos=querypost(1,id,n,now,gcd);
//cout<<"uuauaua"<<endl;
if(pos==0) pos=n+1;
int len=pos-p;
ppost.push_back(pii(now,len));
p=pos;
if(p<=n) now=__gcd(now,a[p]);
}
//cout<<"eeee "<<endl;
for(int i=0; i<ppre.size(); i++)
{
for(int j=0; j<ppost.size(); j++)
{
int num1,num2,len1,len2;
num1=ppre[i].first;
num2=ppost[j].first;
len1=ppre[i].second;
len2=ppost[j].second;
int gcd=__gcd(num1,num2);
cnt[gcd]-=len1*len2;
if(cnt[gcd]==0)
{
ans--;
}
}
}
}
else
{
//cout<<"aaaaaaaaaaaaaaaaaaaaaaaaa"<<endl;
int now=a[id];
int p=id;
while(p>=1)
{
int gcd=a[id];
int pos=querypre(1,1,id,now,gcd);
int len=p-pos;
ppre.push_back(pii(now,len));
p=pos;
if(p>=1) now=__gcd(now,a[p]);
}
//cout<<"eeee "<<endl;
now=a[id];
p=id;
while(p<=n)
{
int gcd=a[id];
//cout<<"yyyyyyyyyyyy"<<endl;
int pos=querypost(1,id,n,now,gcd);
//cout<<"uuauaua"<<endl;
if(pos==0) pos=n+1;
int len=pos-p;
ppost.push_back(pii(now,len));
p=pos;
if(p<=n) now=__gcd(now,a[p]);
}
//cout<<"eeee "<<endl;
for(int i=0; i<ppre.size(); i++)
{
for(int j=0; j<ppost.size(); j++)
{
int num1,num2,len1,len2;
num1=ppre[i].first;
num2=ppost[j].first;
len1=ppre[i].second;
len2=ppost[j].second;
int gcd=__gcd(num1,num2);
if(cnt[gcd]==0) ans++;
cnt[gcd]+=len1*len2;
}
}
}
}
int main()
{
int T;
scanf("%d",&T);
int kk=0;
while(T--)
{
ans=0;
memset(cnt,0,sizeof(cnt));
scanf("%d %d",&n,&q);
for(int i=1; i<=n; i++) scanf("%d",&a[i]);
build(1,1,n);
for(int i=1; i<=n; i++)
{
//cout<<"***** i "<<i<<endl;
int p=i;
int now=a[i];
while(p>=1)
{
int gcd=a[i];
int pos=querypre(1,1,i,now,gcd);
cnt[now]+=p-pos;
//cout<<"now "<<now<<" l "<<pos<<" r "<<p<<endl;
p=pos;
if(p>=1) now=__gcd(now,a[p]);
}
}
for(int i=1;i<NUM;i++) if(cnt[i]) ans++;
//cout<<"ans "<<ans<<endl;
printf("Case #%d:\n",++kk);
int id,val;
while(q--)
{
scanf("%d %d",&id,&val);
solve(id,0);
update(1,id,val);
a[id]=val;
solve(id,1);
printf("%d\n",ans);
}
}
return 0;
}