首页 > 其他分享 >[题解] P4435 [COCI2017-2018#2] ​​Garaža

[题解] P4435 [COCI2017-2018#2] ​​Garaža

时间:2023-11-14 09:22:35浏览次数:38  
标签:pre suf val COCI2017 题解 back Gara int ans

P4435 [COCI2017-2018#2] Garaža

给你一个长度为 \(n\) 的序列 \(a\),单点改,查询区间 \(\gcd\) 不为 1 的子区间个数。
\(n, Q \le 10^5, a_i \le 10^9\)。

先看单次全局查询怎么做。考虑一个分治,每次我们要计算跨过分治中心 \(mid\) 的答案。因为这个是单调的,所以可以双指针做一下。

再加上修改和区间询问,可以把这个分治结构扔到线段树上去维护。但是这个 push_up 是 \(O(n)\) 的,我们需要更快速的 push_up。对于这个有一个经典结论,就是 \(\gcd\) 最多变化 \(\log\) 次,所以可以直接开一个 vector 把每个 gcd 的连续段存下来,这样 push_up 就是 \(O(\log V)\) 的了,求 \(\gcd\) 的复杂度可以被势能分析掉。

时间复杂度 \(O(n \log n \log V)\)。

constexpr int MAXN = 1e5 + 9;
int n, q, a[MAXN];

int Gcd(int a, int b) {
	int az = __builtin_ctz(a), bz = __builtin_ctz(b), z = min(az, bz), t; b >>= bz;
	while (a) a >>= az, t = a - b, az = __builtin_ctz(t), b = min(a, b), a = (t < 0 ? (~t + 1) : t);
	return b << z;
}

struct Node {
	vector<pii> pre, suf;
	ll ans;
	
	Node(): ans(0) { pre.clear(), suf.clear(); return; }
	friend Node operator + (const Node &x, const Node &y) {
		assert(x.pre.size() && x.suf.size() && y.pre.size() && y.suf.size());
		Node ans; ans.ans = x.ans + y.ans;
		{
			int i = 0, j = y.pre.size() - 1, len = 0;
			for (auto [g, l] : y.pre) len += l;
			for (; i < x.suf.size(); i ++) {
				while (j >= 0 && Gcd(x.suf[i].fir, y.pre[j].fir) == 1)
					len -= y.pre[j].sec, j --;
				ans.ans += 1ll * x.suf[i].sec * len;
			}
		}
		ans.pre = x.pre, ans.suf = y.suf;
		int val = ans.pre.back().fir;
		for (auto [g, l] : y.pre)
			if (Gcd(val, g) == val) ans.pre.back().sec += l;
			else ans.pre.emplace_back(val = Gcd(val, g), l);
		val = ans.suf.back().fir;
		for (auto [g, l] : x.suf)
			if (Gcd(val, g) == val) ans.suf.back().sec += l;
			else ans.suf.emplace_back(val = Gcd(val, g), l);
		return ans;
	}
} sgt[MAXN << 2];

void Push_Up(int p) {
	sgt[p] = sgt[p << 1] + sgt[p << 1 | 1];
	return;
}
void Build(int p = 1, int L = 1, int R = n) {
	if (L == R) {
		sgt[p] = Node();
		sgt[p].pre.emplace_back(a[L], 1);
		sgt[p].suf.emplace_back(a[L], 1);
		sgt[p].ans = (a[L] != 1);
		return;
	}
	int Mid = L + R >> 1;
	Build(p << 1, L, Mid), Build(p << 1 | 1, Mid + 1, R);
	Push_Up(p); return;
}
void Update(int pos, int k, int p = 1, int L = 1, int R = n) {
	if (L == R) {
		sgt[p] = Node();
		sgt[p].pre.emplace_back(k, 1);
		sgt[p].suf.emplace_back(k, 1);
		sgt[p].ans = (k != 1);
		return;
	}
	int Mid = L + R >> 1;
	if (pos <= Mid) Update(pos, k, p << 1, L, Mid);
	else Update(pos, k, p << 1 | 1, Mid + 1, R);
	Push_Up(p); return;
}
Node Query(int l, int r, int p = 1, int L = 1, int R = n) {
	if (l <= L && R <= r) return sgt[p];
	int Mid = L + R >> 1;
	if (r <= Mid) return Query(l, r, p << 1, L, Mid);
	if (Mid < l) return Query(l, r, p << 1 | 1, Mid + 1, R);
	return Query(l, r, p << 1, L, Mid) + Query(l, r, p << 1 | 1, Mid + 1, R);
}

void slv() {
	n = Read<int>(), q = Read<int>();
	for (int i = 1; i <= n; i ++) a[i] = Read<int>();
	Build();
	while (q --) {
		int opt = Read<int>();
		if (opt == 1) {
			int pos = Read<int>(), v = Read<int>();
			Update(pos, v);
		} else {
			int l = Read<int>(), r = Read<int>();
			Write(Query(l, r).ans, '\n');
		}
	}
	return;
}

标签:pre,suf,val,COCI2017,题解,back,Gara,int,ans
From: https://www.cnblogs.com/definieren/p/17830899.html

相关文章

  • 【题解】P4768 [NOI2018] 归程 / Kruskal 重构树
    补补以前懒得总结的零碎东西。kruskal重构树使用条件:求无向图中两点之间所有路径的最大边权的最小值构造:依kruskal得到最小生成树从小到大考虑生成树中的边\((u,v)\)对于\((u,v)\),新建一个结点,作为重构树中\(u,v\)的父结点该结点的点权为\((u,v)\)的......
  • SPOJ1805 HISTOGRA - Largest Rectangle in a Histogram 题解
    LinkSPOJ1805HISTOGRA-LargestRectangleinaHistogramQuestion在一条水平线上有\(n\)个高为\(a_i\)的矩形,求包含于这些矩形的最大子矩形面积。Solution我们定义\(L_i\)表示有\(a_i\)这个高度的一根悬线,往左最多能平移到什么位置初始化显然,\(a_i=i\)考虑转移......
  • 题解 AT_codefestival_2016_final_f【Road of the King】
    注意到当前移动到的位置并不重要,重要的是经过的点数和\(1\)所在强连通分量大小,因此把它们放进状态里:设\(f_{i,j,k}\)表示进行\(i\)次移动,经过了\(j\)个不同的点,此时\(1\)所在的强连通分量大小为\(k\)的方案数。考察下一次移动到的点的情况:没有访问过:共有\(n-j\)......
  • UVA11282 题解
    题意简述Kelly寄出去\(n\)封邀请函,但她希望只有小于等于\(m\)个人收到他们自己的邀请函(即有至少\(n-m\)个人收到了别人的邀请函)。思路形成容易发现,这道题是一个典型的错排题,我们只需要分别求出\(n-m\)个元素到\(n\)个元素的错排即可。接下来为错排的推导,我们令\(f......
  • [题解] P4755 Beautiful Pair
    P4755BeautifulPair给你一个长度为\(n\)的序列\(a\),求有多少个区间\([l,r]\)满足\(a_l\cdota_r\le\max_{i=l}^ra_i\)。\(n\le10^5,a_i\le10^9\)。首先按最大值位置分治。记当前分治区间为\([l,r]\),分治中心为\(mid\)。那么我们现在要做的就是统计跨......
  • 【题解 P4062 & P8313】 Yazid 的新生舞会&Izbori
    [COCI2021-2022#4]Izbori题目描述Malnar先生正在竞选县长,这个县一共有\(n\)栋房屋,每栋房屋里都住着一位居民。Malnar先生知道,选举的赢家不一定是最好的候选人,而是在选举前举办的宴会最好的候选人。因此,在选举前几天,他将邀请第\(l\)至\(r(l\ler)\)栋房屋内居住的居民,为......
  • 【题解】CF1891E - Brukhovich and Exams
    【题解】CF1891E-BrukhovichandExamshttps://www.luogu.com.cn/problem/CF1891E我们考虑把区间分段:若两个相邻的数不互素,中间分开;若两个相邻的数中有且仅有一个\(1\),中间分开。那么我们得到了两种区间:全\(1\)区间与无\(1\)区间。若两个相邻数在同一区间内,那么就在区间......
  • [题解] CFgym101623F Factor-Free Tree
    Factor-FreeTree当一棵二叉树中的每个节点的权值都与它所有祖先的权值互质时,我们称它为factor-freetree。给你一棵按照中序遍历的顺序的权值序列\(a\),求这个序列是否对应这一棵factor-freetree。如果是就输出每个节点的父亲。\(n\le10^5,a_i\le10^7\)。考虑怎么......
  • SP2139题解
    思路这题数据范围小,暴力就可以了。首先我们用map来统计每个人的下标,用\(bk_{i,j}\)表示第\(i\)个人第\(j\)题是否知道答案。对于每次合作交流,暴力修改就可以了,先统计出两个人的下标,假设一个为\(x\),另一个为\(y\)。然后,如果\(bk_{x,i}\)和\(bk_{y,i}\)中(\(1\lei......
  • [ARC106E] Medals 题解
    题意有一个商店和\(N\)名员工,其中第\(i\)名员工在第\(1\simA_i\)天工作,在第\(A_i+1\sim2\timesA_i\)休息,接下来每\(A_i\)天改变一次状态。每一天你都可以选择一名来上班的员工并为其颁一个奖,求使得每名员工都获得至少\(K\)个奖的最小天数。\(1\leN\le......