首页 > 其他分享 >【bitset】【线段树】CF633G Yash And Trees 题解

【bitset】【线段树】CF633G Yash And Trees 题解

时间:2023-10-05 22:55:51浏览次数:34  
标签:pr int 题解 Yash tr Trees ++ dfn tag

CF633G

简单题。

先看到子树加和子树质数个数和,果断转换为 dfs 序进行处理。

既然有区间求和,考虑线段树。

若对于每一个节点维护一个 \(cnt\) 数组,用二进制数 \(x\) 来表示,即当 \(cnt_i = 1\) 时第 \(i\) 位为 \(1\)。设当前节点为 \(u\),左右子节点分别为 \(ls\) 和 \(rs\)。发现 \(x_u = x_{ls} | x_{rs}\)。统计时,就是区间的所有 \(x\) 的按位或值 \(res\) 与质数数组所表示的二进制数 \(pr\) 的按位与后 \(1\) 的个数。然后考虑更改,令 \(v\) 为加的数,易得 x_u = (x_u << v & full) | (x_u >> (m - v)),其中 \(full = 2^m - 1\),是防止溢出用的。

都到这一步了,不会还有人不知道怎么优化吧。

既然是二进制的数,用 bitset 进行优化即可。

时间复杂度:\(\mathcal{O}(\dfrac{nm\log n}{w})\)

代码:

const int N = 1e5 + 10, M = 1e3 + 10;
int n, m, Q, tot;
int a[N], b[N];
int tag[N << 2], d[N], siz[N], dfn[N], rdfn[N];
bitset<M> tr[N << 2], pr, f, ans;
int head[N], cnte;
struct edge {
	int v, nxt;
} e[N << 1];
void adde(int u, int v) {
	e[++cnte].nxt = head[u];
	e[cnte].v = v;
	head[u] = cnte;
}
 
void pushup(int u) {
	tr[u] = tr[u << 1] | tr[u << 1 | 1];
}
void pushdown(int u) {
	if (tag[u]) {
		tag[u << 1] = (tag[u << 1] + tag[u]) % m, tag[u << 1 | 1] = (tag[u << 1 | 1] + tag[u]) % m;
		tr[u << 1] = (tr[u << 1] << tag[u]) | (tr[u << 1] >> (m - tag[u]));
		tr[u << 1 | 1] = ((tr[u << 1 | 1] << tag[u]) & f) | (tr[u << 1 | 1] >> (m - tag[u]));
		tag[u] = 0;
	}
}
void build(int u, int l, int r, int *a) {
	if (l == r) {
		tr[u].reset();
		tr[u].set(a[l]);
		return;
	}
	int mid = l + r >> 1;
	build(u << 1, l, mid, a), build(u << 1 | 1, mid + 1, r, a);
	pushup(u);
}
void update(int u, int l, int r, int L, int R, int val) {
	if (L <= l && r <= R) {
		tag[u] = (tag[u] + val) % m;
		tr[u] = ((tr[u] << val) & f) | (tr[u] >> (m - val));
		return;
	}
	pushdown(u);
	int mid = l + r >> 1;
	if (L <= mid) update(u << 1, l, mid, L, R, val);
	if (mid < R) update(u << 1 | 1, mid + 1, r, L, R, val);
	pushup(u);
}
void query(int u, int l, int r, int L, int R) {
	if (L <= l && r <= R) {
		ans |= tr[u];
		return;
	}
	pushdown(u);
	int mid = l + r >> 1;
	if (L <= mid) query(u << 1, l, mid, L, R);
	if (mid < R) query(u << 1 | 1, mid + 1, r, L, R);
}
void dfs_init(int u, int f) {
	d[u] = d[f] + 1, siz[u] = 1, dfn[u] = ++tot, rdfn[tot] = u;
	for (int i = head[u], v; i != 0; i = e[i].nxt)
		if ((v = e[i].v) != f) {
			dfs_init(v, u);
			siz[u] += siz[v];
		}
}
 
int main() {
	ios
	cin >> n >> m;
	for (int i = 0; i < m; i++) f.set(i);
	for (int i = 2; i < m; i++) pr.set(i);
	for (int i = 2; i < m; i++)
		if (pr[i]) {
			for (int j = 2 * i; j < m; j += i)
				pr.reset(j);
		}
	for (int i = 1; i <= n; i++) {
		cin >> a[i];
		a[i] %= m;
	}
	for (int i = 1, u, v; i < n; i++) {
		cin >> u >> v;
		adde(u, v), adde(v, u);
	}
	dfs_init(1, 0);
	for (int i = 1; i <= n; i++) b[i] = a[rdfn[i]];
	build(1, 1, n, b);
	cin >> Q;
	while (Q--) {
		int opt, u, x;
		cin >> opt >> u;
		if (opt == 1) {
			cin >> x;
			update(1, 1, n, dfn[u], dfn[u] + siz[u] - 1, x % m);
		} else {
			ans.reset();
			query(1, 1, n, dfn[u], dfn[u] + siz[u] - 1);
			int res = (ans & pr).count();
			cout << res << "\n";
		}
	}
	return 0;
}

标签:pr,int,题解,Yash,tr,Trees,++,dfn,tag
From: https://www.cnblogs.com/Pengzt/p/17744068.html

相关文章

  • 【倍增】P3422 [POI2005]LOT-A Journey to Mars 题解
    P3422一道有点意思的题。看到是一个环,先破环为链,即\(a_{n+i}=a_i,b_{n+i}=b_i\),此时就只需要跳到\(x+n\)而无需判环了。如果顺时针走:令\(sum_i=\sum\limits_{j=1}^{i}{a_j-b_j}\),当能从\(x\)跳到\(x+n\)时,有\[sum_{x-1}\lesum_x,sum_{x-1}\lesum_{x+1},\dot......
  • 【DP】ABC273F Hammer 2 题解
    ABC273F一道比较板的区间\(\text{dp}\)。先对坐标离散化,令离散化数组为\(v\)。令\(f_{i,j}\)表示能走到区间\([v_i,v_j]\)的最短路程,显然\(f\)数组初始为\(inf\)。但发现这样无法转移,可以再增加一维\(k\in\{0,1\}\),表示此时在\([v_i,v_j]\)的\(v_i/v_j\)处。......
  • 【线段树合并】CF1805E There Should Be a Lot of Maximums 题解
    CF1805E待补:有另解看到维护树上问题,可以想到线段树合并。但直接维护显然不行,要一点技巧。发现\(val\)的出现次数\(cnt_{val}\)如果\(\ge3\),那么一定是一个候选项,若\(cnt_{val}=1\),那么一定不能作为候选项。于是可以用权值线段树维护对于\(val\)有\(cnt_{val}=......
  • [ABC257F] Teleporter Setting 题解
    1.题目洛谷传送门2.思路我们可以把不确定的点当成真实存在的\(0\)号点,建边的时候就正常连即可。然后我们来看一个样例:1-2-03-4-5当我们把\(0\)号点看成\(3\)号点时,答案就是\(1\)号点到\(0\)号点的距离加上\(3\)号点到\(5\)号点的距离。然后我们再......
  • 【思维】【DP】ABC298Ex Sum of Min of Length 题解
    ABC298Ex简单题。因为有\(\min\)不好做,容易想到讨论\(d(i,L)\)和\(d(i,R)\)的大小。令\(p=\text{LCA}(L,R)\),\(dep_L>dep_R,dist=dep_L+dep_R-2\timesdep_p\),\(now\)满足\(dep_L-dep_{now}=\lfloor\dfrac{dist}{2}\rfloor\)则\(L\)一定在......
  • 【图论】【寻找性质】CF1151E Number of Components 题解
    CF1151E发现每一个\(f(l,r)\)中的连通块总是一条链(一棵树)。那么此时连通块的数量就等于点的数量减去边的数量。先考虑点的总数,一个价值为\(a_i\)的点一定是在\(l\leqslanta_i\)且\(r\geqslanta_i\)的\(f(l,r)\)中才会有一个贡献,根据乘法原理,它会产生\(a_i\time......
  • 【二分】P7795 [COCI2014-2015#7] PROSJEK 题解
    P7795典。显然\(\mathcal{O}(n^2)\)的时间复杂度无法通过。使子段平均值最大,考虑二分。可以二分平均值\(mid\),然后判断是否有满足条件的子段.时间复杂度:\(\mathcal{O}(\dfrac{n\log\max\{a_i\}}{\text{eps}})\),其中\(\text{eps}\)为设置的精度,\(\max\{a_i\}\leq10......
  • P8565 Sultan Rage 题解
    P8565发现数列\(a\)增长的特别快,项数最多时是\(a_1=a_2=\cdots=a_{100}\),但这样也只会有一百多项就可以超过\(10^{18}\)。可以考虑搜索,因为搜索树会比较稀疏,函数dfs(val,cur)表示凑出\(x\)还需要\(val\),现在在考虑\(cur\)。但光是搜索肯定不能过这道题,考虑优......
  • P4133 [BJOI2012]最多的方案 题解
    P4133双倍经验发现斐波那契数列增长极快,不到\(100\)项就超过了\(10^{18}\),搜索树也极为稀疏,可以考虑搜索。爆搜肯定会超时,考虑优化:可行性剪枝。记忆化,去除重复的计算。改变搜索的顺序,因为先考虑小元素的话,会有较多的无用的搜索,且小元素较灵活,更容易凑到\(x\),故可......
  • 【竞赛图】【DP】ARC163D Sum of SCC 题解
    ARC163D发现这个竞赛图一定能被分为两个集合\(A\),\(B\)。满足\(\forallu\inA,v\inB\),均有\(u\tov\inE\)。答案就是划分这两个集合的方案数。证明:首先,竞赛图缩完点后一定是一条链,对强连通分量进行标号,满足编号小的强连通分量指向编号大的强连通分量。不妨令竞赛图\(G\)......