Sum

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 4247    Accepted Submission(s): 1211

 

Problem Description

XXX is puzzled with the question below:

1, 2, 3, ..., n (1<=n<=400000) are placed in a line. There are m (1<=m<=1000) operations of two kinds.

Operation 1: among the x-th number to the y-th number (inclusive), get the sum of the numbers which are co-prime with p( 1 <=p <= 400000).
Operation 2: change the x-th number to c( 1 <=c <= 400000).

For each operation, XXX will spend a lot of time to treat it. So he wants to ask you to help him.

 

 

Input

There are several test cases.
The first line in the input is an integer indicating the number of test cases.
For each case, the first line begins with two integers --- the above mentioned n and m.
Each the following m lines contains an operation.
Operation 1 is in this format: "1 x y p".
Operation 2 is in this format: "2 x c".

 

 

Output

For each operation 1, output a single integer in one line representing the result.

 

 

Sample Input

1

3 3

2 2 3

1 1 3 4

1 2 3 6

 

 

Sample Output

7

0

 

 

Source

​2012 ACM/ICPC Asia Regional Jinhua Online ​

 

 

Recommend

zhoujiaqi2010   |   We have carefully selected several similar problems for you:  ​​6396​​​ ​​6395​​​ ​​6394​​​ ​​6393​​​ ​​6392​​ 算法分析:

题意:

给一个长度为n的序列,序列由1~n依次组成。 
对序列执行两种操作: 
1.查询[x,y]内与p互素的数的和;
2.修改第x数为c.

分析:

与以往容斥原理不同,这回不叫计数,而叫求和了,想了好久,上网是一个等比数列,公式套用就行。

对于操作二,想到只能暴力搜索,操作数不多,能过。Vector保存修改的值话需要判重,map就不用了。

 

最坑爹的是map做的代码超时,这无所谓,但它竟然因为gcd()函数,把它改成int,760ms过。

我知道了,刚才又交了一发,把map<int,int>改为long long就对了。也就是说,你查找的数据必须和map类型中对应。

但vector做的long long 却过了,玄学啊

代码实现:

Map

#include<cstdio>  
#include<cstring>
#include<cstdlib>
#include<cctype>
#include<cmath>
#include<iostream>
#include<sstream>
#include<iterator>
#include<algorithm>
#include<string>
#include<vector>
#include<set>
#include<map>
#include<stack>
#include<deque>
#include<queue>
using namespace std;
typedef long long ll;
long long ans=0,sum=0,r;
ll fac[105];
map<int,int>Map;
int gcd(int a,int b)
{//求最大公约数
return b?gcd(b,a%b):a;
}
void factor(ll m)
{
sum = 0;
ll tmp = m;
for(ll i = 2; i*i<=tmp; i++) //官方版的唯一分解定理
if(tmp%i==0)
{
fac[sum++] = i;
while(tmp%i==0) tmp /= i;
}
if(tmp>1) fac[sum++] = tmp;
}
ll getsum(ll n)
{//等差数列求和公式
return (n+1)*n/2;//注意(n+1)/2*n这样不对
}
void dfs(int i,int cnt,int tmp)//i代表数组的下标
{ //cnt代表几个元素的最小公倍数

if(cnt&1) //容斥原理
ans+=(ll)tmp*getsum(r/tmp);
else
ans-=(ll)tmp*getsum(r/tmp);

for(int j=i+1;j<sum;j++)
dfs(j,cnt+1,tmp*fac[j]);
}
long long sub(long long ans,int a,int b,int p)///修改
{
map<int,int>::iterator it;
for(it=Map.begin();it!=Map.end();it++)
{
int f1=gcd(p,it->second);
int f2=gcd(p,it->first);
if(it->first<=b&&it->first>=a)
{
if(f1==1) ans+=it->second;
if(f2==1) ans-=it->first;
}
}
return ans;
}
int main()
{
int T;
cin>>T;
while(T--)
{
Map.clear();

int n,m;
ll sum1=0;
scanf("%d%d",&n,&m);
for(int i=1;i<=m;i++)
{
int x,y,a,b;
scanf("%d",&a);

if(a==2)
{
scanf("%d%d",&x,&b);
Map[x]=b;
}
else
{
sum1=0;
sum=0;
ans=0;

scanf("%d%d%d",&x,&y,&b);
factor(b);
r=x-1;
for(int j=0;j<sum;j++)
{
dfs(j,1,fac[j]);
}

sum1=getsum(x-1)-ans;

r=y;
ans=0;
for(int j=0;j<sum;j++)
{
dfs(j,1,fac[j]);
}
sum1=getsum(y)-ans-sum1;
cout<<sub(sum1,x,y,b)<<endl;
}
}
}
}

Vector

#include<cstdio>  
#include<cstring>
#include<cstdlib>
#include<cctype>
#include<cmath>
#include<iostream>
#include<sstream>
#include<iterator>
#include<algorithm>
#include<string>
#include<vector>
#include<set>
#include<map>
#include<stack>
#include<deque>
#include<queue>
using namespace std;
typedef long long ll;
long long ans=0,sum=0,r;
ll fac[105];
ll gcd(ll a,ll b)
{//求最大公约数
return b?gcd(b,a%b):a;
}
void factor(ll m)
{
sum = 0;
ll tmp = m;
for(ll i = 2; i*i<=tmp; i++) //官方版的唯一分解定理
if(tmp%i==0)
{
fac[sum++] = i;
while(tmp%i==0) tmp /= i;
}
if(tmp>1) fac[sum++] = tmp;
}
ll getsum(ll n)
{//等差数列求和公式
return (n+1)*n/2;//注意(n+1)/2*n这样不对
}
void dfs(int i,int cnt,int tmp)//i代表数组的下标
{ //cnt代表几个元素的最小公倍数

if(cnt&1) //容斥原理
ans+=(ll)tmp*getsum(r/tmp);
else
ans-=(ll)tmp*getsum(r/tmp);

for(int j=i+1;j<sum;j++)
dfs(j,cnt+1,tmp*fac[j]);
}
struct node
{
int x,c;
}w;
vector<node> v;
int main()
{
int T;
cin>>T;
int t=0;

while(T--)
{
v.clear();
t++;
int n,m;
ll sum1=0;
scanf("%d%d",&n,&m);
for(int i=1;i<=m;i++)
{
int x,y,a,b;
scanf("%d",&a);

if(a==2)
{

scanf("%d%d",&w.x,&w.c);
int flag=1;
//判断该位置是否已经修改过了
for(int j=0;j<v.size();j++)
if(v[j].x==w.x)
{
flag=0;
v[j].c=w.c;
break;
}
if(flag) v.push_back(w);
}
else
{
sum1=0;
sum=0;
ans=0;

scanf("%d%d%d",&x,&y,&b);
factor(b);
r=x-1;
for(int j=0;j<sum;j++)
{
dfs(j,1,fac[j]);
}
sum1=getsum(x-1)-ans;


r=y;
ans=0;
for(int j=0;j<sum;j++)
{
dfs(j,1,fac[j]);
}
sum1=getsum(y)-ans-sum1;

for(int j=0;j<v.size();j++)
{
if(v[j].x<=y&&v[j].x>=x)
{
if(gcd(b,v[j].x)==1)
sum1-=v[j].x;
if(gcd(b,v[j].c)==1)
sum1+=v[j].c;
}
}
cout<<sum1<<endl;
}
}
}
}