GCD
Time Limit: 9000/4500 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others)Total Submission(s): 343 Accepted Submission(s): 78
Problem Description
Mr. Frog likes generating numbers! He can generate many numbers from a sequence.
For a given sequence a1,a2,⋯,an Mr. Frog can choose two numbers l and r ( 1≤l≤r≤n ) and calculate the gcd between l-th and r-th number in this sequence g=gcd(al,al+1,⋯,ar) . Asan expert in generating numbers, Mr. Frog wants to know how many distinct numbers can be generated by a sequence.
Mr. Frog likes challenges, so there may be many modifications in this sequence. In the i-th modification, Mr. Frog may change ap to vi . After each modification, you are asked to tell how many distinct numbers can be generated by this sequence immediately!
For a given sequence a1,a2,⋯,an Mr. Frog can choose two numbers l and r ( 1≤l≤r≤n ) and calculate the gcd between l-th and r-th number in this sequence g=gcd(al,al+1,⋯,ar) . Asan expert in generating numbers, Mr. Frog wants to know how many distinct numbers can be generated by a sequence.
Mr. Frog likes challenges, so there may be many modifications in this sequence. In the i-th modification, Mr. Frog may change ap to vi . After each modification, you are asked to tell how many distinct numbers can be generated by this sequence immediately!
Input
The first line contains only one integer T, which indicates the number of test cases.
For each test case, the first line includes two numbers n, q( 1≤n,q≤50000 ). which indicate the length of sequence and the number of modifications.
The second line contains n numbers: a1,a2,⋯,an .
Then q lines, each line contain two numbers, pi,vi(1≤pi≤n,1≤vi≤1000000) .
Test data guarantee that 1<≤ai≤1000000 all the time and the sum of all n and q is less than or equal to 2×105 .
For each test case, the first line includes two numbers n, q( 1≤n,q≤50000 ). which indicate the length of sequence and the number of modifications.
The second line contains n numbers: a1,a2,⋯,an .
Then q lines, each line contain two numbers, pi,vi(1≤pi≤n,1≤vi≤1000000) .
Test data guarantee that 1<≤ai≤1000000 all the time and the sum of all n and q is less than or equal to 2×105 .
Output
For each test case, first output one line "Case #x:", where x is the case number (starting from 1). Then q lines, each line contain only one number, which is the answer to current sequence.
Sample Input
2 3 2 1 2 3 1 3 2 3 3 2 3 3 3 1 1 2 2
Sample Output
Case #1: 3 1 Case #2: 2 3HintFor case 1, after the first operation, 3,2,1 can be generated by the sequence 3, 2, 3. Whereas after the second operation, sequence 3, 3, 3 can generate only 3.
Source
Recommend
wange2014
题意:给一个序列,每次改变一个位置的值,求每次更新后有多少种不同的连续的序列的gcd
解题思路:先一遍扫出一共有几种gcd,每种gcd有几个,建一棵线段树用来求区间gcd。每次修改一个位置的值时,先分别向左和向右求出未更新前以这个位置为端点有几种gcd,每种gcd有几个,然后向左和向右产生的gcd合并算一下,每种gcd减去产生的数量。然后修改线段树上的gcd,再向左和向右求出更新后以这个位置为端点有几种gcd,每种gcd有几个,然后向左和向右产生的gcd合并算一下,每种gcd加上产生的数量
#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <algorithm>
#include <queue>
#include <stack>
#include <cmath>
#include <map>
#include <bitset>
#include <set>
#include <vector>
#include <functional>
using namespace std;
#define LL long long
const int INF = 0x3f3f3f3f;
int n, q;
int a[50009], xx[50009 * 4], sum;
LL visit[1000009];
struct node
{
int x, sum;
} b[50009], c[50009];
int gcd(int x, int y)
{
return x%y ? gcd(y, x%y) : y;
}
void build(int k, int l, int r)
{
if (l == r) { xx[k] = a[l]; return; }
int mid = (l + r) >> 1;
build(k << 1, l, mid);
build(k << 1 | 1, mid + 1, r);
xx[k] = gcd(xx[k << 1], xx[k << 1 | 1]);
}
void update(int k, int l, int r, int p, int val)
{
if (l == r) { xx[k] = val; a[p] = val; return; }
int mid = (l + r) >> 1;
if (p <= mid) update(k << 1, l, mid, p, val);
else update(k << 1 | 1, mid + 1, r, p, val);
xx[k] = gcd(xx[k << 1], xx[k << 1 | 1]);
}
int query(int k, int l, int r, int ll, int rr)
{
if (rr < ll) return 0;
if (ll <= l&&r <= rr) return xx[k];
int mid = (l + r) >> 1;
int ans1 = 0, ans2 = 0;
if (ll <= mid) ans1 = query(k << 1, l, mid, ll, rr);
if (rr > mid) ans2 = query(k << 1 | 1, mid + 1, r, ll, rr);
if (ans1&&ans2) return gcd(ans1, ans2);
if (ans1) return ans1;
else return ans2;
}
int queryl(int k, int l, int r, int rr, int val)
{
if (xx[k] % val == 0) return l;
if (l == r) return 0;
int mid = (l + r) >> 1, res1, res2;
if (rr > mid)
{
res2 = queryl(k << 1 | 1, mid + 1, r, rr, val);
if (res2 == mid + 1)
{
res1 = queryl(k << 1, l, mid, rr, val);
if (!res1) return res2;
else return res1;
}
return res2;
}
return queryl(k << 1, l, mid, rr, val);
}
int queryr(int k, int l, int r, int ll, int val)
{
if (xx[k] % val == 0) return r;
if (l == r) return 0;
int mid = (l + r) >> 1,res1,res2;
if (ll <= mid)
{
res1 = queryr(k << 1, l, mid, ll, val);
if (res1 == mid)
{
res2 = queryr(k << 1 | 1, mid + 1, r, ll, val);
if (!res2) return res1;
return res2;
}
return res1;
}
return queryr(k << 1 | 1, mid + 1, r, ll, val);
}
void f(int p, int flag)
{
int cnt1 = 1, cnt2 = 1, k = p, kk = a[p];
b[cnt1].x = a[p];
while (k >= 1)
{
int ans = queryl(1, 1, n, p, kk);
b[cnt1++].sum = (k - ans + 1);
k = ans - 1;
kk = query(1, 1, n, k, p);
b[cnt1].x = kk;
}
k = p, kk = a[p];
c[cnt2].x = a[p];
while (k <= n)
{
int ans = queryr(1, 1, n, p, kk);
c[cnt2++].sum = (ans - k + 1);
k = ans + 1;
kk = query(1, 1, n, p, k);
c[cnt2].x = kk;
}
for (int i = 1; i < cnt1; i++)
{
for (int j = 1; j < cnt2; j++)
{
k = gcd(b[i].x, c[j].x);
if (!visit[k]) sum++;
if (flag) visit[k] += 1LL * b[i].sum*c[j].sum;
else visit[k] -= 1LL * b[i].sum*c[j].sum;
if (!visit[k]) sum--;
}
}
}
int main()
{
int t, cas = 0;
scanf("%d", &t);
while (t--)
{
printf("Case #%d:\n", ++cas);
scanf("%d%d", &n, &q);
memset(visit, 0, sizeof visit);
sum = 0;
stack<pair<int, int>>s1, s2;
for (int i = 1; i <= n; i++)
{
scanf("%d", &a[i]);
s1.push(make_pair(a[i], 1));
while (!s1.empty()) s2.push(make_pair(gcd(s1.top().first, a[i]), s1.top().second)), s1.pop();
while (!s2.empty())
{
pair<int, int>pre = s2.top(); s2.pop();
if (!visit[pre.first]) sum++;
visit[pre.first] += pre.second;
while (!s1.empty() && s1.top().first == pre.first) pre.second += s1.top().second, s1.pop();
s1.push(pre);
}
}
build(1, 1, n);
while (q--)
{
int p, v;
scanf("%d%d", &p, &v);
f(p, 0);
update(1, 1, n, p, v);
f(p, v);
printf("%d\n", sum);
}
}
return 0;
}