【HDU5930 2016CCPC东北地区大学生程序设计竞赛 - 重现赛 I】【线段树 预处理加变更贡献】GCD 动态修改维护全局gcd数量

GCD

Time Limit: 9000/4500 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 78    Accepted Submission(s): 11


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 ( 1lrn ) 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( 1n,q50000 ). 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(1pin,1vi1000000) .

Test data guarantee that   1<ai1000000  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 3
Hint
For 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


#include<stdio.h>
#include<iostream>
#include<string.h>
#include<string>
#include<ctype.h>
#include<math.h>
#include<set>
#include<map>
#include<vector>
#include<queue>
#include<bitset>
#include<algorithm>
#include<time.h>
using namespace std;
void fre() { freopen("c://test//input.in", "r", stdin); freopen("c://test//output.out", "w", stdout); }
#define MS(x,y) memset(x,y,sizeof(x))
#define rt 1, 1, n
#define ls o<<1
#define rs o<<1|1
#define lson o<<1,l,mid
#define rson o<<1|1,mid+1,r
typedef long long LL;
typedef unsigned long long UL;
typedef unsigned int UI;
template <class T1, class T2>inline void gmax(T1 &a, T2 b) { if (b>a)a = b; }
template <class T1, class T2>inline void gmin(T1 &a, T2 b) { if (b<a)a = b; }
const int N = 5e4 + 10, M = 0, Z = 1e9 + 7, inf = 0x3f3f3f3f;
template <class T1, class T2>inline void gadd(T1 &a, T2 b) { a = (a + b) % Z; }
int casenum, casei;
int n, m;
int a[1 << 17];	//a[i]维护线段树第i个节点的区间gcd值
int b[N];		//b[i]维护第i个位置的数值
int gcd(int x, int y)
{
	return y == 0 ? x : gcd(y, x%y);
}
void pushup(int o)
{
	a[o] = gcd(a[ls], a[rs]);
}
void build(int o, int l, int r)
{
	if (l == r)
	{
		a[o] = b[l];
		return;
	}
	int mid = (l + r) >> 1;
	build(lson);
	build(rson);
	pushup(o);
}
int P, V;
void modify(int o, int l, int r)
{
	if (l == r)
	{
		a[o] = V;
		return;
	}
	int mid = (l + r) >> 1;
	P <= mid ? modify(lson) : modify(rson);
	pushup(o);
}
int L, R, G, TP;
int query(int o, int l, int r)
{
	if (l >= L && r <= R && a[o] % G == 0)return 0;
	if (l == r)return l;
	int mid = (l + r) >> 1;
	int tmp = 0;
	if (TP == 0)
	{
		if (R > mid)tmp = query(rson);
		if (tmp)return tmp;
		if (L <= mid)return query(lson);
	}
	else
	{
		if (L <= mid)tmp = query(lson);
		if (tmp)return tmp;
		if (R > mid)return query(rson);
	}
	return tmp;
}
vector< pair<int, int> >lft, rgt;
LL cnt[1000010];int ans;
int dfn[1000010]; int tim;
void cal(int P, int sig, bool init = 0)
{
	lft.clear();
	rgt.clear();
	int i, p;
	//get lft
	TP = 0; p = P;
	for (i = p, G = b[p]; i >= 1; i = p, G = gcd(G, b[p]))
	{
		L = 1; R = i;
		p = query(rt);
		lft.push_back({ i - p, G });
	}
	//get rgt
	if (!init)
	{
		TP = 1; p = P;
		for (i = p, G = b[p]; i <= n; i = p, G = gcd(G, b[p]))
		{
			L = i; R = n;
			p = query(rt); if (p == 0) p = n + 1;
			rgt.push_back({ p - i, G });
		}
	}
	else rgt.push_back({ 1, b[p] });
	for (auto l : lft)
	{
		for (auto r : rgt)
		{
			LL num = (LL)l.first * r.first;
			int g = gcd(l.second, r.second);
			if (dfn[g] != tim)dfn[g] = tim, cnt[g] = 0;
			if (cnt[g] == 0)++ans;
			cnt[g] += num * sig;
			if (cnt[g] == 0)--ans;
		}
	}
}
void init()
{
	for (int i = 1; i <= n; ++i)cal(i, 1, 1);
}
int main()
{
	scanf("%d", &casenum);
	for (casei = 1; casei <= casenum; ++casei)
	{
		scanf("%d%d", &n, &m);
		for (int i = 1; i <= n; ++i)scanf("%d", &b[i]);
		build(rt);
		++tim; 
		ans = 0;
		init(); 
		printf("Case #%d:\n", casei);
		for (int i = 1; i <= m; ++i)
		{
			scanf("%d%d", &P, &V);
			cal(P, -1);
			b[P] = V;
			modify(rt);
			cal(P, 1);
			printf("%d\n", ans);
		}
	}
	return 0;
}
/*
【题意】
有n(50000)个数a[](1e6范围)和q(50000)个操作
对于每个操作,我们会修改a[p]为v
问你每次修改之后会剩下多少个不同的区间连续gcd

【类型】
数据结构

【分析】
一个点的gcd值会影响所有包含其的区间
我们先预处理出n(n+1)个区间的gcd值,用一个cnt数组完成计数
然后对于修改,我们查询出包含这个点的所有区间段(这个可以通过在线段树上二分实现),在cnt数组中消除即可
然后再修改,再在cnt数组中加回去完成计数即可
复杂度的瓶颈在于我们合并区间时的左log个gcd区间和右log的gcd区间再求gcd导致的(log)^3

【时间复杂度&&优化】
O(nlognlognlogn)

【数据】
input
2
3 2
1 2 3
1 3
2 3
ans
3 1

input 
3 2
3 3 3
1 1
2 2
ans
2 3
*/


评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值