【题目描述】

有 n 个正整数 x1~xn,初始时状态均为未选。有 m 个操作,每个操作给定一个编号 i,将 xi 的选取状态取反。每次操作后,你需要求出选取的数中有多少个互质的无序数对。

【输入数据】

第一行两个整数 n,m。第二行 n 个整数 x1~xn。接下来 m 行每行一个整数。

【输出数据】

m 行,每行一个整数表示答案。

【样例输入】

4 5 1 2 3 4 1 2 3 4 1

【样例输出】

0 1 3 5 2

【数据范围】

对于 20%的数据,n,m<=1000。对于另外 30%的数据,xi<=100。对于 100%的数据,n,m<=200000,xi<=500000,1<=i<=n。

分析:
    对带有询问修改的问题我们可以先想出无询问无修改的问题解决方法,然后将解法组织成易于修改和回答询问的形式。

    那么对于这道题,无修改无询问则是:给出n个数,求出n个数中互质的无序数对个数。

    让我们考虑互质的本质——没有大于1的公因子,即GCD(a,b)==1。这样的数学题我们清楚地知道一一枚举是没有好结果的,通常情况下这类问题可以朝两大方向思考:组合数与容斥原理。

    由于本题不存在方案数、概率等的计算,因此我们尝尝容斥原理的味道。

    既然企图使用容斥,那么定几个表示有关联数组是很有必要的:
        ·f(i)表示GCD为i的 #include<stdio.h>
#define ll long long
#define go(i,a,b) for(int i=a;i<=b;i++)
;
int n,m,a[N],I,x,d,Mob[N];
ll s[N],g[N],f[N],ans;bool get[N];
struct Sieve
{
int prime[N],t;bool no[N];
void Mobius_Sieve()
{
Mob[]=;
go(i,,){;
go(j,,t){)break;
Mob[i*prime[j]]=i%prime[j]?-Mob[i]:;
no[i*prime[j]]=;)break;}}
}
}Tool;
int main()
{
Tool.Mobius_Sieve();
scanf("%d%d",&n,&m);
go(i,,n)scanf("%d",a+i);
while(m--)
{
scanf("%d",&I);x=a[I];
d=()?:-;
go(i,,x)&&i*i<=x)
{
s[i]+=d;if(i!=x/i)
s[x/i]+=d;

ans-=Mob[i]*g[i];if(i!=x/i)
ans-=Mob[x/i]*g[x/i];

g[i]=s[i]*(s[i]-)/;if(i!=x/i)
g[x/i]=s[x/i]*(s[x/i]-)/;

ans+=Mob[i]*g[i];if(i!=x/i)
ans+=Mob[x/i]*g[x/i];
}
else if(i*i>x)break;
printf("%lld\n",ans);
}
;
}//Paul_Guderian