题意:给一串数字1,2,......n,两个操作:1、修改第k个数字,2、查询区间[l,r]中与n互质的数之和。
解题思路:咱一看,像线段树,但是如果用线段树做,那么每个区间一定要记录所有的素因子,这样会超内存。然后我就做不来了。后来看了题解,原来是用容斥原理来做的。还记得这道题目吗?求区间[1,r]中与p互质的数的个数,如果不会的话就先去做那题吧。现在这题是求区间[l,r]中与n互质的数的和,先求[1,r]中与n不互质的数字的和,然后做差求与n互质的数的和。由于更新操作只有1000次,所以暴力判断在区间[l,r]内更新过的点。时间复杂度是多少呢,运算比较复杂,但是可以证明时间复杂度并不高。
代码如下:
#include<iostream>
#include<algorithm>
#include<stdio.h>
#include<math.h>
#include<cstring>
#include<string>
#include<vector>
#include<map>
#define LL __int64
#define N 450000
#define inf 0x3f3f3f3f
#define pi acos(-1.0)
#define eps 10e-6
using namespace std;
int pri[N],tot,vis[N];
vector<int> q;
map<int,int> mp;
map<int,int>::iterator it;
void get_primes()
{
memset(vis,0,sizeof(vis));
tot = 0;
int i,m = sqrt(N+0.5);
for(i = 2; i <= m; i++)
{
if(vis[i] == 0) pri[tot++] = i;
for(LL j = 1LL*i*i; j <= m; j+=i)
vis[j] = 1;
}
}
void get_primes_of_n(int n)
{
q.clear();
int i;
for(i = 0; i < tot && pri[i]*pri[i] <= n; i++)
{
if(n%pri[i] == 0)
{
q.push_back(pri[i]);
while(n%pri[i] == 0)
n /= pri[i];
}
}
if(n > 1) q.push_back(n);
}
LL get_sum(int n)
{
int len = q.size();
int m = (1<<len);
LL ans = 0;
int i,j;
for(i = 1; i < m; i++)
{
int cnt = 0,a0 = 1;
for(j = 0; j < len; j++)
if(i&(1<<j))
{
cnt++;
a0 *= q[j];
}
int k = n/a0;
int an = a0+a0*(k-1);
LL sum = 1LL*(an+a0)*k/2;
if(cnt&1) //+
ans += sum;
else ans -= sum;
}
return ans;
}
int gcd(int a,int b)// a<b
{
return b%a == 0 ? a : gcd(b%a,a);
}
int main()
{
get_primes();
int t;
scanf("%d",&t);
while(t--)
{
int n,m;
scanf("%d%d",&n,&m);
mp.clear();
while(m--)
{
int op;
scanf("%d",&op);
if(op == 2)
{
int x,c;
scanf("%d%d",&x,&c);
mp[x] = c;
}
else
{
int x,y,p;
scanf("%d%d%d",&x,&y,&p);
get_primes_of_n(p);//得到p的质因子
LL ans = 1LL*(x+y)*(y-x+1)/2;
LL temp = get_sum(y)-get_sum(x-1);
ans -= temp;
for(it = mp.begin(); it != mp.end(); it++)
{
if(it->first < x || it->first > y) continue;
int k1 = p,k2 = it->first;
if(k1 > k2) swap(k1,k2);
if(gcd(k1,k2) == 1)
ans -= it->first;
k1 = p;k2 = it->second;
if(k1 > k2) swap(k1,k2);
if(gcd(k1,k2) == 1) ans += it->second;
}
printf("%I64d\n",ans);
}
}
}
return 0;
}